USACO Section 2.3

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值