您的位置:首页 > 大数据 > 人工智能

[USACO Training] Section 2.3

2016-08-22 10:27 330 查看

PROB Longest Prefix

给定一些(length 1..200)小字符串(length 1..10)和一个大字符串(length 1..200,000),求大字符串的前缀中能由小字符串拼接得到的最大长度。

递推,朴素地比较就可以。看到字符串这么长,朴素地比较有点虚……想到NOI 2016 Day1 T1和前辈用strcmp水阿狸的打字机的故事,我决定试一试。正如ANALYSIS所言,字符串比较的最坏情况不易达到,常数也小;可以用Trie优化。

写以下代码的时候我忘记了
strncmp
这个东西。

/*
ID: chrt2001
PROG: prefix
LANG: C++
*/
#include <cstdio>
#include <cstring>
using namespace std;
char p[201][11], s[200001];
int l[200];
bool f[200000];
int main()
{
freopen("prefix.in", "r", stdin);
freopen("prefix.out", "w", stdout);
int m = 0, n = 0, ans = 0;
while ((~scanf("%s", p[m])) && p[m][0] != '.') {
l[m] = strlen(p[m]);
++m;
}
while (~scanf("%s", s+n))
while (s
)
++n;
char c;
for (int i = 0; i < n; ++i) {
c = s[i+1];
s[i+1] = 0;
for (int j = 0; j < m; ++j)
if (i+1 >= l[j] && (i-l[j] == -1 || f[i-l[j]]) && strcmp(s+i-l[j]+1, p[j]) == 0) {
f[i] = true;
ans = i+1;
break;
}
s[i+1] = c;
}
printf("%d\n", ans);
return 0;
}


PROB Cow Pedigrees

求一共有N个(3 <= N < 200)结点、高度为K(1 < K < 100)、每个结点有0或2个儿子的树的个数,对9901取模。

联想到两个东西:一是卡特兰数,二是用高度小于等于K的减去高度小于等于(K-1)的得到高度等于K的。

本题的名字和某wiki很像。

/*
ID: chrt2001
PROG: nocows
LANG: C++
*/
#include <cstdio>
using namespace std;
const int M = 9901;
int f[100][200];

int main()
{
freopen("nocows.in", "r", stdin);
freopen("nocows.out", "w", stdout);
int n, k;
scanf("%d %d", &n, &k);
if (n % 2 == 0 || k > n/2+1) {
puts("0");
return 0;
}
f[1][1] = 1;
for (int i = 2; i <= k; ++i) {
f[i][1] = 1;
for (int j = 3; j <= n; j += 2)
for (int t = 1; t < j-1; t += 2)
f[i][j] = (f[i][j] + f[i-1][t]*f[i-1][j-1-t]) % M;
}

printf("%d\n", (f[k]
- f[k-1]
+ M) % M);
return 0;
}


PROB Zero Sum

求在1~n <= 9之间填
+
-
或不填,结果为0的表达式,按字典序输出。

枚举一下就好。我是一边枚举一边计算的,也可以像ANALYSIS那样最后再算。

/*
ID: chrt2001
PROG: zerosum
LANG: C++
*/
#include <cstdio>
using namespace std;
enum op {BEGIN, BLANK=' ', PLUS='+', MINUS='-'};
char s[10];
int n;

inline void print()
{
putchar('1');
for (int i = 2; i <= n; ++i)
printf("%c%d", s[i], i);
putchar('\n');
}

// k ~ 当前数字;x ~ 上一个数;r ~ 先前的结果;pre ~ 上一个非空操作;now ~ 当前操作
void search(int k, int x, int r, op pre, op now)
{
s[k] = char(now);
switch (now) {
case BLANK:
if (pre == PLUS)
r += 9*x + k;
else
r -= 9*x + k;
x = 10*x + k;
break;

case PLUS:
r += k;
x = k;
break;

case MINUS:
r -= k;
x = k;
}

if (k == n) {
if (r == 0)
print();
return;
}

op o = now == BLANK ? pre : now;

search(k+1, x, r, o, BLANK);
search(k+1, x, r, o, PLUS);
search(k+1, x, r, o, MINUS);
}

int main()
{
freopen("zerosum.in", "r", stdin);
freopen("zerosum.out", "w", stdout);
scanf("%d", &n);
search(1, 0, 0, BEGIN, PLUS);
return 0;
}


PROB Money Systems

那个作为错误贪心范例的经典DP问题。

注意这里隐含着滚动数组,所以不能把两维循环的顺序搞反。(开始我搞反了QAQ)

/*
ID: chrt2001
PROG: money
LANG: C++
*/
#include <cstdio>
using namespace std;
typedef long long ll;
const int MAX_N = 10000, MAX_V = 25;
ll f[MAX_N+1];
int c[MAX_V];
int main()
{
freopen("money.in", "r", stdin);
freopen("money.out", "w", stdout);
int v, n;
scanf("%d %d", &v, &n);
for (int i = 0; i < v; ++i)
scanf("%d", &c[i]);
f[0] = 1;
for (int i = 0; i < v; ++i)
for (int j = 1; j <= n; ++j)
f[j] += (j >= c[i] ? f[j-c[i]] : 0);
printf("%lld\n", f
);
return 0;
}


PROB Controlling Companies

公司A拥有公司B当且仅当满足下述条件中至少一个:

- A=B。

- A拥有B大于50%的股权。

- A拥有的公司中拥有B的股权之和大于50%。

给定一些股权所有信息,求所有的拥有关系,不用输出自己拥有自己。公司不超过100个。

从每个点开始BFS。用队列维护它拥有的点,向外更新。

ANALYSIS用了诡异的递归。

/*
ID: chrt2001
PROG: concom
LANG: C++
*/
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAX_N = 100, MAX_P = 50;
bool control[MAX_N+1][MAX_N+1];
int n, M[MAX_N+1][MAX_N+1], p[MAX_N+1];
queue<int> Q;

void search(int x)
{
memset(p+1, 0, sizeof(int)*n);
Q.push(x);
control[x][x] = true;
int u;
while (!Q.empty()) {
u = Q.front();
Q.pop();
for (int v = 1; v <= n; ++v)
if (M[u][v]) {
p[v] += M[u][v];
if (p[v] > MAX_P && !control[x][v]) {
Q.push(v);
control[x][v] = true;
}
}
}
}

int main()
{
freopen("concom.in", "r", stdin);
freopen("concom.out", "w", stdout);
int m;
scanf("%d", &m);
for (int i = 0; i < m; ++i) {
int x, y, p;
scanf("%d %d %d", &x, &y, &p);
n = max(n, max(x, y));
M[x][y] += p;
}
for (int i = 1; i <= n; ++i)
search(i);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
if (control[i][j] && i != j)
printf("%d %d\n", i, j);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  动态规划 bfs 枚举