7月29集训训练个人赛第五场
2013-07-29 10:58 bootstar 阅读(226) 评论(0) 编辑 收藏 举报A Codeforces 126B
KMP。直接计算next数组就可以了,然后按照next数组的值直接判定是否存在一个子串长度满足条件即可。
1 #include <stdio.h> 2 #include <string.h> 3 const int maxn = 1000005; 4 char src[maxn]; 5 int f[maxn]; 6 7 void getFail(char *src){ 8 f[1] = 0; 9 int cur = 0; 10 for(int i = 2; src[i]; i ++){ 11 while(src[cur + 1] != src[i] && cur) cur = f[cur]; 12 if(src[cur + 1]==src[i]) f[i] = ++ cur; 13 else f[i] = cur = 0; 14 } 15 } 16 bool check(int len){ 17 int x = 0; 18 for(int i = 1; src[i]; i ++){ 19 x = x + (f[i] >= len); 20 } 21 if(x < 2) return false; 22 return true; 23 } 24 int main(){ 25 //freopen("test.in", "r", stdin); 26 for(;scanf("%s", src + 1)!=EOF;){ 27 memset(f, 0, sizeof(f)); 28 getFail(src); 29 int len = strlen(src+1); 30 int ans = f[len]; 31 if(ans == 0){ 32 printf("Just a legend\n"); 33 continue; 34 } 35 if(len%(len - ans) == 0 && (len/(len - ans) > 2)){ 36 for(int i = 1; i <= len - 2*(len - ans); i ++) 37 putchar(src[i]); 38 putchar('\n'); 39 continue; 40 } 41 42 for(;!check(ans) && ans; ans = f[ans]); 43 if(ans == 0){ 44 printf("Just a legend\n"); 45 } 46 else{ 47 for(int i = 1; i <= ans; i ++){ 48 putchar(src[i]); 49 } 50 putchar('\n'); 51 } 52 } 53 return 0; 54 }
B Codeforces 315E
树状数组或者线段树。问题是统计序列的每个子序列的要写的序列的个数。直接看代码吧,表示已经不晓得怎么解释了。或者去看官方题解好了。。http://codeforces.com/blog/entry/7905
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 using namespace std; 5 #define MOD 1000000007 6 const int maxn = 1000005; 7 typedef long long LL; 8 LL A[maxn], B[maxn]; 9 10 #define LOWBIT(x) ((x)&(-x)) 11 void add(int x, LL y){ 12 while(x < maxn){ 13 A[x] = (A[x] + y)%MOD; 14 x += LOWBIT(x); 15 } 16 } 17 LL getSum(int x){ 18 LL sum = 0; 19 while(x){ 20 sum = (sum + A[x])%MOD; 21 x -= LOWBIT(x); 22 } 23 return sum%MOD; 24 } 25 int main(){ 26 int n, x; 27 cin>>n; 28 LL ans = 0; 29 for(int i = 1; i <= n; i ++){ 30 cin>>x; 31 LL cur = getSum(x); 32 cur = (cur*x+x)%MOD; 33 ans = (ans + cur - B[x])%MOD; 34 add(x, cur - B[x]); 35 B[x] = cur; 36 } 37 cout<<(ans%MOD+MOD)%MOD<<endl; 38 return 0; 39 }
C Codeforces 242E
线段树的裸题。可以将和拆分成二进制位计算就可以了,剩余的就是赤果果的线段树了。
1 #include <stdio.h> 2 #include <string.h> 3 typedef long long LL; 4 const int maxn = 100005; 5 const int SIZE = 21; 6 7 #define lson(c) (c<<1) 8 #define rson(c) (c<<1|1) 9 #define mid(l, r) ((l+r)/2) 10 11 struct Tree{ 12 int f[maxn*4][SIZE]; 13 int s[maxn*4]; 14 void push_up(int c){ 15 int l = lson(c); 16 int r = rson(c); 17 for(int i = 0; i < SIZE; i ++){ 18 f[c][i] = f[l][i] + f[r][i]; 19 } 20 s[c] = 0; 21 } 22 void push_down(int c, int l, int r){ 23 int ls = lson(c); 24 int rs = rson(c); 25 int t = s[c]; 26 int md = mid(l, r); 27 if(s[c]==0) return; 28 29 for(int i = 0; i < SIZE; i ++, t >>= 1){ 30 if(t&1){ 31 f[ls][i] = (md - l + 1) - f[ls][i]; 32 f[rs][i] = (r - md) - f[rs][i]; 33 } 34 } 35 s[ls]^=s[c]; 36 s[rs]^=s[c]; 37 } 38 void build(int c, int l, int r){ 39 s[c] = 0; 40 if(l==r){ 41 int x; scanf("%d", &x); 42 for(int i = 0; i < SIZE; i ++){ 43 f[c][i] = x&1; x>>=1; 44 } 45 return; 46 } 47 build(lson(c), l, mid(l, r)); 48 build(rson(c), mid(l, r) + 1, r); 49 push_up(c); 50 } 51 void update(int c, int l, int r, int lp, int rp, int x){ 52 if(lp <= l && rp >= r){ 53 s[c] ^= x; 54 for(int i = 0; i < SIZE; i ++, x>>=1){ 55 if(x&1) f[c][i] = (r - l + 1) - f[c][i]; 56 } 57 return ; 58 } 59 push_down(c, l, r); 60 int md = mid(l, r); 61 if(rp <= md) update(lson(c), l, md, lp, rp, x); 62 else if(lp > md) update(rson(c), md + 1, r, lp, rp, x); 63 else{ 64 update(lson(c), l, md, lp, md, x); 65 update(rson(c), md + 1, r, md + 1, rp, x); 66 } 67 push_up(c); 68 } 69 void query(int c, int l, int r, int lp, int rp, int ans[]){ 70 if(lp <= l && rp >= r){ 71 for(int i = 0; i < SIZE; i ++){ 72 ans[i] += f[c][i]; 73 } 74 return; 75 } 76 push_down(c, l, r); 77 int md = mid(l, r); 78 if(rp <= md) query(lson(c), l, md, lp, rp, ans); 79 else if(lp > md) query(rson(c), md + 1, r, lp, rp, ans); 80 else{ 81 query(lson(c), l, md, lp, md, ans); 82 query(rson(c), md + 1, r, md + 1, rp, ans); 83 } 84 push_up(c); 85 } 86 }tree; 87 88 int main(){ 89 //freopen("test.in", "r", stdin); 90 for(int n, m; scanf("%d", &n)!=EOF;){ 91 tree.build(1, 1, n); 92 int ans[32]; 93 scanf("%d", &m); 94 for(int i = 1, l, r, t; i <= m; i ++){ 95 scanf("%d%d%d", &t, &l, &r); 96 if(t==1){ 97 memset(ans, 0, sizeof(ans)); 98 tree.query(1, 1, n, l, r, ans); 99 LL answer = 0; 100 for(int i = 0, x = 1; i < SIZE; i ++){ 101 answer = answer + (LL)x * ans[i]; 102 x<<=1; 103 } 104 printf("%I64d\n", answer); 105 } 106 else{ 107 int x; 108 scanf("%d", &x); 109 tree.update(1, 1, n, l, r, x); 110 } 111 } 112 } 113 return 0; 114 }
D Codeforces 11D
状态压缩,dp[mask][i]表示遍历mask中的所有点并以最小标号的点为起点,以i点为终点的简单路径的个数。集合与路径上的动态规划http://codeforces.com/blog/entry/337
1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int maxn = 20; 6 typedef long long LL; 7 int g[maxn][maxn]; 8 LL d[1<<maxn][maxn]; 9 LL ans; 10 11 inline bool bit(int i, int mask){ 12 return mask&(1<<i); 13 } 14 inline int first(int mask){ 15 int r; 16 for(r = 0; !(mask &(1<<r)); r ++); 17 return r; 18 } 19 inline int count(int mask){ 20 int c = 0; 21 for(; mask; mask>>=1){ 22 c += (mask&1); 23 } 24 return c; 25 } 26 LL dfs(int mask, int ep, int n){ 27 int cnt = count(mask), sp = first(mask); LL sum = 0; 28 if(d[mask][ep]>=0) return d[mask][ep]; 29 for(int p = first(mask); p < n; p ++){ 30 if(p != ep && bit(p, mask) && g[p][ep] && (cnt==2||p != sp)){ 31 sum = sum + dfs(mask^(1<<ep), p, n); 32 } 33 } 34 if(cnt > 2 && g[ep][sp]) 35 ans += sum; 36 return (d[mask][ep] = sum); 37 } 38 int main(){ 39 //freopen("test.in", "r", stdin); 40 for(int n, m; scanf("%d%d", &n, &m)!=EOF; ){ 41 memset(g, 0, sizeof(g)); 42 memset(d, -1, sizeof(d)); 43 for(int i = 1, x, y; i <= m; i ++){ 44 scanf("%d%d", &x, &y); 45 x --, y --; 46 g[x][y] = g[y][x] = 1; 47 } 48 int mask = 1<<n; 49 ans = 0; 50 for(int i = 0; i < n; i ++) 51 d[1<<i][i] = 1; 52 for(int i = 1; i < mask; i ++){ 53 if(count(i)>1){ 54 int sp = first(i); 55 for(int j = sp; j < n; j ++){ 56 if(bit(j, i) && g[sp][j]){ 57 dfs(i, j, n); 58 } 59 } 60 } 61 } 62 printf("%I64d\n", ans/2); 63 } 64 65 return 0; 66 }
E POJ 1285
水题。求多重组合,母函数或者DP搞。母函数就很直接了,每一种选取的个数为0-a[i],所以直接套模板就是了。母函数的相关资料: http://www.wutianqi.com/?p=596。
DP,dp[i][j]表示从前i重物品中选取j件的表示方法,所以dp[i][j] = sigma(dp[i-1][j-x]) 其中x <= a[i],a[i]表示第i件物品的个数。
1 #include <stdio.h> 2 #include <string.h> 3 typedef long long LL; 4 int cnt[55]; 5 LL A[55], B[55]; 6 7 int findNext(int c){ 8 for(int i = c + 1; i <= 51; i ++){ 9 if(cnt[i]) return i; 10 } 11 return -1; 12 } 13 14 void process(){ 15 memset(A, 0, sizeof(A)); 16 memset(B, 0, sizeof(B)); 17 int c, r = 0; 18 c = findNext(0); 19 for(int i = 0; i <= cnt[c]; i ++){ 20 A[i] = 1; 21 } 22 r = cnt[c]; 23 while((c = findNext(c))!=-1){ 24 for(int i = 0; i <= r; i ++){ 25 for(int j = 0; j <= cnt[c]; j ++){ 26 B[i+j] += A[i]; 27 } 28 } 29 r += cnt[c]; 30 for(int i = 0; i <= r; i ++){ 31 A[i] = B[i], B[i] = 0; 32 } 33 } 34 } 35 36 int main(){ 37 int n, m; 38 for(int kcas = 1;scanf("%d%d", &n, &m)!=EOF, n||m; kcas ++){ 39 memset(cnt, 0, sizeof(cnt)); 40 for(int i = 1; i <= n; i ++){ 41 int d; scanf("%d", &d); 42 cnt[d] ++; 43 } 44 process(); 45 printf("Case %d:\n", kcas); 46 for(int i = 1; i <= m; i ++){ 47 int d; scanf("%d", &d); 48 printf("%I64d\n", A[d]); 49 } 50 } 51 return 0; 52 }
F Codeforces 146E
DP 首先考虑到为lucky的数字只有1300多个,这样就可以DP了。首先统计出不同lucky数字的个数,以及每个lucky出现的次数,排个序,然后dp[i][j]表示从前i个lucky数中选取j个的选择办法, dp[i][j] = dp[i-1][j] + c[i] * dp[i-1][j-1],其中c[i]表示第i个lucky出现的次数。然后枚举选择lucky数的个数,答案就是sigma(dp[l][x] * C[s][k-x]),其中l表示lucky数的不同个数,s表示非lucky数的个数。
1 #include <stdio.h> 2 #include <map> 3 #include <string.h> 4 #include <algorithm> 5 using namespace std; 6 #define maxn 1500 7 typedef long long LL; 8 const LL mod = 1000000007; 9 LL dp[maxn][maxn], C[100005]; 10 map<int, int> hash; 11 12 bool check(int a){ 13 for(;a; a/=10){ 14 if(a%10!=4&&a%10!=7) return false; 15 } 16 return true; 17 } 18 19 void extgcd(LL a, LL b, LL&g, LL&x, LL&y){ 20 if(b==0){ 21 g = a, x = 1, y = 0; return; 22 } 23 extgcd(b, a%b, g, y, x); 24 y -= a/b*x; 25 } 26 27 LL inv(LL a){ 28 LL g, x, y; 29 extgcd(a, mod, g, x, y); 30 return (x + mod)%mod; 31 } 32 int main(){ 33 for(int n, k; scanf("%d%d", &n, &k)!=EOF; ){ 34 hash.clear(); 35 int nl = 0, nu = 0; 36 for(int i = 1, x; i <= n; i ++){ 37 scanf("%d", &x); 38 if(check(x)) { 39 if(hash.count(x)==0){ 40 hash.insert(make_pair(x, 1)); 41 nl ++; 42 } 43 else hash[x] ++; 44 } 45 else nu ++; 46 } 47 dp[0][0] = 1; 48 int l = 1; 49 for(map<int, int>::iterator it = hash.begin(); it != hash.end(); it ++){ 50 dp[l][0] = 1; 51 for(int j = 1; j <= l; j ++){ 52 dp[l][j] = (dp[l-1][j] + (it->second) * dp[l-1][j-1]%mod)%mod; 53 } 54 l ++; 55 } 56 memset(C, 0, sizeof(C)); 57 C[0] = 1; 58 for(int i = 0; i < nu; i ++){ 59 C[i + 1] = (C[i] * (nu - i)%mod)*inv(i+1)%mod; 60 } 61 LL ans = 0; 62 for(int x = 0; x <= k && x <= hash.size(); x ++){ 63 ans = (ans + dp[nl][x] * C[k-x]%mod)%mod; 64 } 65 printf("%I64d\n", ans); 66 } 67 return 0; 68 }