USACO Section 2.3
第二题看的题解
The Longest Prefix
/*
ID: beihai2013
TASK: prefix
LANG: C++
*/
/*
考虑到需要匹配前缀的长度和字符串的总长度,我们对需要匹配的前缀进行HASH
然后就O(n*10)的简单判断,如果当前hash值在匹配前缀的字符串中HASH值存在的话,说明匹配成功
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 200 + 5;
const int MAXM = 10 + 1;
const int MAXN1 = 200000 + 5;
char pre[MAXN][MAXM];
char s[MAXN1], str[80];
int precnt;
bool vis[MAXN1];
vector<LL>has[MAXM];
bool exsit(LL temp, int len)
{
vector<LL>::iterator mark = lower_bound(has[len].begin(), has[len].end(), temp);
if(mark != has[len].end() && *mark == temp) return true;
else return false;
}
int main()
{
freopen("prefix.in", "r", stdin);
freopen("prefix.out", "w", stdout);
precnt = 0;
scanf("%s", pre[precnt++]);
// while(scanf("%s", pre[precnt++]) != EOF) {
for(int i = 0 ; i < MAXM ; i++) has[i].clear();
while(pre[precnt - 1][0] != '.') {
int len = strlen(pre[precnt - 1]);
LL temp = 0;
for(int i = 0 ; i < len ; i++) temp = temp * 26 + pre[precnt - 1][i] - '0';
has[len].push_back(temp);
scanf("%s", pre[precnt++]);
}
for(int i = 1 ; i < MAXM ; i++) sort(has[i].begin(), has[i].end());
int res = 0;
int n = 0;
while(scanf("%s", str) != EOF) {
int len = strlen(str);
for(int i = 0 ; i < len ; i++) s[++n]= str[i];
}
for(int i = 0 ; i <= n ; i++) vis[i] = false;
vis[0] = true;
for(int i = 0 ; i <= n ; i++) {
if(vis[i] == false) continue;
LL temp = 0;
for(int j = 1 ; j < MAXM && i + j <= n ; j++) {
temp = temp * 26 + s[i + j] - '0';
if(exsit(temp, j)) vis[i + j] = true, res = max(res, i + j);
}
}
printf("%d\n", res);
return 0;
}
Cow Pedigrees
/*
ID: beihai2013
TASK: nocows
LANG: C++
*/
/*
看的题解
树形dp[i][j]表示深度为i,点数为j(换过来也可以,原理近似)
一般树形dp的时候自己只考虑节点的值,这次按照子树合并考虑
深度为i的树,可以看成是两个子树加上根节点合成(其中肯定有一个子树深度是i-1),而不能看成在原树上加点
那么转移方程很快就出来了,在init中
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define MOD (9901)
const int MAXN = 200 + 5;
const int MAXM = 100 + 5;
LL dp[MAXM][MAXN], sum[MAXM][MAXN];
bool vis[MAXM][MAXN];
int n, m;
void init()
{
memset(dp, 0, sizeof dp);
memset(sum, 0, sizeof sum);
dp[1][1] = sum[1][1] = 1;
for(int i = 2 ; i < MAXM ; i++) {
for(int j = 1 ; j < MAXN ; j++) {
for(int k = 1 ; k < j ; k++) {
dp[i][j] = (dp[i][j] + dp[i - 1][k] * sum[i - 2][j - 1 - k] * 2) % MOD;
dp[i][j] = (dp[i][j] + dp[i - 1][k] * dp[i - 1][j - 1 - k]);
}
sum[i][j] = (sum[i - 1][j] + dp[i][j]);
}
}
}
int main()
{
freopen("nocows.in", "r", stdin);
freopen("nocows.out", "w", stdout);
init();
while(scanf("%d%d", &n, &m) != EOF) printf("%lld\n", dp[m][n]);
return 0;
}
Zero Sum
/*
ID: beihai2013
TASK: zerosum
LANG: C++
*/
/*
三进制枚举
坑点是三进制枚举的时候有些状态是不能用三进制表示的,所以注意这种枚举跳过
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 9 + 3;
int n;
int ppow(int u, int x)
{
int res = 1;
while(x) {
if(x & 1) res = res * u;
x >>= 1;
u = u * u;
}
return res;
}
int sign[MAXN];
int cal()
{
int res = 0;
int flag = 1;
int pre = 1;
for(int i = 2 ; i <= n ; i++) {
if(sign[i] == 0) pre = pre * 10 + i;
else if(sign[i] == 1) {
res = res + flag * pre;
pre = i;
flag = 1;
}
else if(sign[i] == 2) {
res = res + flag * pre;
pre = i;
flag = -1;
}
}
res = res + flag * pre;
return res;
}
void print()
{
printf("1");
for(int i = 2 ; i <= n ; i++) {
if(sign[i] == 0) printf(" ");
else if(sign[i] == 1) printf("+");
else if(sign[i] == 2) printf("-");
printf("%d", i);
}
printf("\n");
}
int main()
{
freopen("zerosum.in", "r", stdin);
freopen("zerosum.out", "w", stdout);
while(scanf("%d", &n) != EOF) {
int up = ppow(3, n - 2);
for(int s = 0 ; s < ppow(3, n - 1) ; s++) {
int ts = s;
int temp = up;
for(int i = 2 ; i <= n ; i++) {
if(ts >= 2 * temp) {
sign[i] = 2;
ts -= 2 * temp;
}
else if(ts >= temp) {
sign[i] = 1;
ts -= temp;
}
else sign[i] = 0;
temp = temp / 3;
}
if(ts != 0) continue;
temp = cal();
// if(temp == 0) {
// for(int i = 2 ; i <= n ; i++) printf("%d ", sign[i]);
// puts("");
// system("pause");
// }
if(temp == 0) print();
}
}
return 0;
}
Money Systems
/*
ID: beihai2013
TASK: money
LANG: C++
*/
/*
ÂãÍêÈ«±³°ü
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 10000 + 5;
const int MAXM = 25 + 3;
int v[MAXM], n, m;
LL dp[MAXN];
int main()
{
freopen("money.in", "r", stdin);
freopen("money.out", "w", stdout);
while(scanf("%d%d", &m, &n) != EOF) {
for(int i = 1 ; i <= m ; i++) scanf("%d", v + i);
memset(dp, 0, sizeof dp);
dp[0] = 1;
for(int i = 1 ; i <= m ; i++) {
for(int j = 0 ; j <= n - v[i] ; j++) {
if(dp[j] == 0) continue;
else dp[j + v[i]] += dp[j];
}
}
printf("%lld\n", dp[n]);
}
return 0;
}
Controlling Companies
/*
ID: beihai2013
TASK: concom
LANG: C++
*/
/*
每个点topo一下
坑点是n只是表示边数,点的范围永远是[1,100]
*/
#include <bits/stdc++.h>
using namespace std;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
typedef pair<int,int> pii;
const int MAXN = 100 + 5;
vector<pii>e[MAXN];
int n, in[MAXN], tin[MAXN], vis[MAXN], dp[MAXN];
bool con[MAXN];
queue<int>que;
pii out[MAXN * MAXN];
int outcnt;
void topo(int st)
{
for(int i = 1 ; i < MAXN ; i++) vis[i] = 0, tin[i] = in[i], dp[i] = 0, con[i] = false;
while(!que.empty()) que.pop();
que.push(st);
vis[st] = 1, con[st] = 1, dp[st] = 100;
while(!que.empty()) {
int u = que.front(); que.pop();
for(int i = 0 ; i < (int)e[u].size() ; i++) {
int v = e[u][i].fi;
tin[v]--;
dp[v] += e[u][i].se;
// printf("u = %d, v = %d, e = %d %d, dp[v] = %d\n", u, v, e[u][i].fi, e[u][i].se, dp[v]);
if(dp[v] > 50) con[v] = true;
if(con[v] == true && vis[v] == 0) {
que.push(v);
vis[v] = 1;
}
}
}
for(int i = 1 ; i < MAXN ; i++) {
if(con[i] && i != st) out[outcnt++] = mp(st, i);
}
}
int main()
{
freopen("concom.in", "r", stdin);
freopen("concom.out", "w", stdout);
while(scanf("%d", &n) != EOF) {
for(int i = 1 ; i < MAXN ; i++) e[i].clear(), in[i] = 0;
for(int i = 1 ; i <= n; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
e[u].pb(mp(v, w));
in[v]++;
}
outcnt = 0;
for(int i = 1 ; i < MAXN ; i++) topo(i);
sort(out, out + outcnt);
for(int i = 0 ; i < outcnt ; i++) printf("%d %d\n", out[i].fi, out[i].se);
}
return 0;
}