代码改变世界

8月1日集训训练个人赛第六场

2013-08-01 20:21  bootstar  阅读(198)  评论(0编辑  收藏  举报

A Codeforces 223C

按照题目要求多画几个找找系数的规律---杨辉三角

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <assert.h>
 4 
 5 #define maxn 2005
 6 typedef long long LL;
 7 const LL mod = 1000000007;
 8 LL C[maxn][maxn];
 9 LL a[maxn], s[maxn];
10 
11 void gcd(LL a, LL b, LL&d, LL &x, LL &y){
12     if(!b){d = a, x = 1, y = 0;}
13     else{
14         gcd(b, a%b, d, y, x);
15         y -= x*(a/b);
16     }
17 }
18 LL inv(LL a, LL n){
19     LL d, x, y;
20     gcd(a, n, d, x, y);
21     return d == 1 ? (x+n)%n : -1;
22 }
23 void init(int n, int K){
24     C[0][0] = 1;
25     for(int i = 1; i <= n; i ++){
26         LL t = inv(i, mod);
27         assert( t != -1);
28         t = t * (K - i + 1)%mod;
29         C[0][i] = t * C[0][i-1]%mod;
30     }
31     for(int i = 1; i < n; i ++){
32         for(int j = i; j < n; j ++){
33             C[i][j] = (C[i-1][j-1] + C[i-1][j])%mod;
34         }
35     }
36 
37 }
38 int main(){
39     LL n, k;
40     scanf("%I64d%I64d", &n, &k);
41     for(int i = 1; i <= n; i ++){
42         scanf("%I64d", &a[i]);
43     }
44     if(k==0){
45         for(int i = 1; i <= n; i ++){
46             printf("%I64d ", a[i]);
47         }
48         return 0;
49     }
50     init(n, k-1);
51     for(int i = 1; i <= n; i ++){
52         for(int j = i; j <= n; j ++){
53             s[j] = (s[j] + C[j-i][j-i]*a[i]%mod)%mod;
54         }
55     }
56     for(int i = 1; i <= n; i ++){
57         printf("%I64d ", s[i]);
58     }
59     printf("\n");
60     return 0;
61 }
View Code

B POJ 3244

Max{a, b,c} - min{a, b, c} = (abs(a-b) + abs(b-c) + abs(a-c))/2

D(Ta, Tb) = max{Ia-Ib, Ja-Jb, Ka-Kb} - min{Ia-Ib, Ja-Jb, Ka-Kb}

= (abs(Ia-Ib - Ja+Jb) + abs(Ja-Jb-Ka+Kb) + abs(Ia-Ib-Ka+Kb))/2

Ia-Ja = Wa, Ja-Ka=Ua, Ia-Ka=Ha

=(abs(Wa-Wb) + abs(Ua-Ub) + abs(Ha-Hb))/2

有了这个之后,分别算出Wa,Ua,Ha然后排个序扫描一下就可以了。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define maxn 200005
 6 typedef long long LL;
 7 int A[maxn], B[maxn], C[maxn];
 8 int main(){
 9     int n, p, q, r;
10     while(scanf("%d", &n), n){
11         for(int i = 0; i < n; i ++){
12             scanf("%d%d%d", &p, &q, &r);
13             A[i] = p - q;
14             B[i] = q - r;
15             C[i] = r - p;
16         }
17         sort(A, A + n);
18         sort(B, B + n);
19         sort(C, C + n);
20         LL ans = 0;
21         for(int i = 0; i < n; i ++){
22             ans += (LL)(2*i - n)*(A[i] + B[i] + C[i]);
23         }
24         printf("%I64d\n", ans/2);
25     }
26     return 0;
27 }
View Code

C Codeforces 27D

2-sat,根据条件建边然后dfs寻找是否会存在冲突就可以了。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <vector>
 4 #include <algorithm>
 5 using namespace std;
 6 pair<int, int> p[105];
 7 vector<int> g[105];
 8 bool mark[105], ispart = true;
 9 int color[105];
10 
11 bool check(int x, int y){
12     if(p[x].first < p[y].second && p[x].first > p[y].first && p[x].second > p[y].second)
13         return true;
14     if(p[y].first < p[x].second && p[y].first > p[x].first && p[y].second > p[x].second)
15         return true;
16     return false;
17 }
18 void dfs(int v, int c){
19     mark[v] = 1;
20     color[v] = c;
21     for(int i = 0; i < g[v].size(); i ++){
22         int u = g[v][i];
23         if(!mark[u]) dfs(u, c^1);
24         else if(mark[u]==1 && color[u]==c) ispart = false;
25     }
26     mark[v] = 2;
27 }
28 int main(){
29     //freopen("test.in", "r", stdin);
30     for(int n, m; scanf("%d%d", &n, &m)!=EOF; ){
31         memset(mark, 0, sizeof(mark));
32         ispart = true;
33         for(int i = 0, a, b; i < m; i ++){
34             scanf("%d%d", &a, &b);
35             p[i].first = min(a, b);
36             p[i].second = max(a, b);
37         }
38         for(int i = 0; i < m; i ++){
39             for(int j = i + 1; j < m; j ++){
40                 if(check(i, j)){
41                     g[i].push_back(j);
42                     g[j].push_back(i);
43                 }
44             }
45         }
46         for(int i = 0; i < m; i ++){
47             if(mark[i]==0){
48                 dfs(i, 1);
49                 if(!ispart){
50                     printf("Impossible\n");
51                     break;
52                 }
53             }
54         }
55         if(!ispart) continue;
56         for(int i = 0; i < m; i ++){
57             putchar(color[i] ? 'o' : 'i');
58         }
59     }
60     return 0;
61 }
View Code

D Codeforces 160D

至少存在一棵最小生成树中,这种情况只能是存在于相同权值的边中。每次对同一权值的一同处理。用并查集的时候,如果某个时候一条边的两个端点属于同一个集合,显然此时该边不会被选上去,属于none。对于剩余的边,显然至少会出现一次。我们利用剩余的边对树进行建图,显然此时图中割边是必须出现在任意最小生成树中。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 const int maxn = 100010;
 6 
 7 struct EDGE{
 8     int st, to, id, w, next;
 9 }edge[2*maxn];
10 struct Edge{
11     int st, to, id, w;
12     bool operator<(const Edge&a)const{
13         return w < a.w;
14     }
15 }e[maxn];
16 
17 typedef int arr[maxn];
18 arr head, vis, low, dfn, f, g, h;
19 int tot;
20 
21 void add(int a, int b, int edgeid){
22     edge[tot].to = b;
23     edge[tot].id = edgeid;
24     edge[tot].next = head[a];
25     head[a] = tot++;
26 }
27 
28 void dfs(int u, int fa, int depth){
29     low[u] = dfn[u] = depth;
30     vis[u] = 1;
31     for(int i = head[u]; i != -1; i = edge[i].next){
32         int v = edge[i].to;
33         if(vis[v]==1 && edge[i].id != fa)
34             low[u] = min(low[u], dfn[v]);
35         else if(!vis[v]){
36             dfs(v, edge[i].id, depth + 1);
37             low[u] = min(low[u], low[v]);
38             if(low[v] > dfn[u]){
39                 h[edge[i].id] = 2;
40             }
41         }
42     }
43     vis[u] = 2;
44 }
45 int find(int x){
46     return x==f[x] ? x : (f[x] = find(f[x]));
47 }
48 
49 int main(){
50     //freopen("test.in", "r", stdin);
51     for(int n, m; scanf("%d%d", &n, &m)!=EOF;){
52         for(int i = 1; i <= n; i ++) f[i] = i, h[i] = 0;
53         for(int i = 0; i < m; i ++){
54             scanf("%d%d%d", &e[i].st, &e[i].to, &e[i].w);
55             h[i] = 0;
56             e[i].id = i;
57         }
58         sort(e, e + m);
59         memset(head, -1, sizeof(head));
60         tot = 0;
61         for(int i = 0; i < m; ){
62             int s = i, j, fx, fy;
63             for(j = i; j < m && e[j].w == e[i].w; j ++){
64                 fx = find(e[j].st), fy = find(e[j].to);
65                 if(fx==fy) continue;
66                 h[e[j].id] = 1;
67                 add(fx, fy, e[j].id);
68                 add(fy, fx, e[j].id);
69                 g[j] = fx;
70             }
71             i = j;
72             for(j = s; j < i; j ++){
73                 if(g[j] && !vis[g[j]]){
74                     dfs(g[j], -1, 1);
75                 }
76             }
77             for(j = s; j < i; j ++){
78                 fx = find(e[j].st), fy = find(e[j].to);
79                 if(fx!=fy){
80 
81                     vis[fx] = vis[fy] = 0;
82                     head[fx] = head[fy] = -1;
83                     f[fx] = fy;
84                 }
85             }
86             tot = 0;
87         }
88         for(int i = 0; i < m; i ++){
89             if(h[i]==0) printf("none\n");
90             else if(h[i]==1) printf("at least one\n");
91             else printf("any\n");
92         }
93     }
94     return 0;
95 }
View Code

E Codeforces 21D

经过每条边至少一次回到起点,欧拉回路性质,无向图中所有点的度数必须是偶数。

对于度数为奇数的点肯定是成对出现的,并且,我们只需要在度数为奇数的点上加边就可以使得整个图变成一个包含欧拉回路的图。所以先做floyd,然后状态压缩,配对奇点。

 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <algorithm>
 4 using namespace std;
 5 #define maxn 17
 6 #define inf 0x3f3f3f3f
 7 int g[maxn][maxn];
 8 int h[maxn], f[1<<maxn], d[maxn];
 9 
10 void floyd(int n){
11     for(int k = 0; k < n; k ++){
12         for(int i = 0; i < n; i ++){
13             for(int j = 0; j < n; j ++){
14                 g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
15             }
16         }
17     }
18 }
19 int first(int mask){
20     int r = 0;
21     for(;!(mask&1);r ++, mask>>=1);
22     return r;
23 }
24 bool test(int mask, int b){
25     return (mask&(1<<b));
26 }
27 
28 int main(){
29     //freopen("test.in", "r", stdin);
30     for(int n, m; scanf("%d%d", &n, &m)!=EOF; ){
31         memset(g, 0x3f, sizeof(g));
32         memset(f, 0x3f, sizeof(f));
33         memset(d, 0, sizeof(d));
34 
35         int answer = 0, cnt = 0;
36         for(int i = 0; i < n; i ++) g[i][i] = 0;
37         for(int i = 1, x, y, w; i <= m; i ++){
38             scanf("%d%d%d", &x, &y, &w);
39             x--, y--;
40             answer += w;
41             g[x][y] = g[y][x] =  min(g[x][y], w);
42             d[x] ++, d[y] ++;
43         }
44         floyd(n);
45         bool flag = false;
46         for(int i = 0; i < n; i ++){
47             if(g[0][i]==inf && d[i]){
48                 flag = true;
49                 break;
50             }
51             if(d[i]%2)
52                 h[cnt++] = i;
53         }
54         if(flag){
55             printf("-1\n");
56             continue;
57         }
58         int S = 1<<cnt;
59         f[0] = 0;
60         for(int i = 1; i < S; i ++){
61             int sp = first(i);
62             for(int j = sp + 1; j < cnt; j ++){
63                 if(!test(i, j)) continue;
64                 int mask = i^(1<<sp)^(1<<j);
65                 f[i] = min(f[i], f[mask] + g[h[sp]][h[j]]);
66             }
67         }
68         if(cnt!=0) answer += f[S-1];
69         printf("%d\n", answer);
70     }
71     return 0;
72 }
View Code

F POJ 3372

结论是如果一个数不是2^x次方的形式,肯定是No,否则是Yes。代码很简短

下面主要看证明过程:

首先我们将编号调整为从0开始进行编号,也就是0.....n-1

0次是0,第1次是1,第2次是3.。。第k次便是0+1+2+...+k

也就是第k次发的人的编号是k*(k+1)/2%n,设f(k) = k*(k+1)/2

那么现在的问题便是是不是存在k使得0~n-1中每个数都被取到。

首先对于n是奇数的情况容易发现k=n-1的时候,f(k) = f(n-1) = n*(n-1)/2

由于n是奇数,所以f(n-1)%n=0,另外考虑到f(n) = 0, 所以有f(n+k)=f(k),其中

k<n,所以由鸽巢原理,n个数中有两个值是相同的,所以此时肯定不会使得0~n-1中的每个数字都被取到。

再来看n是偶数的情况,也就是说n=2*r的形式。

对于f(n)=n*(n+1)/2是没有上述的性质了,但是是不是就不存在一个数使得f(x+k)=f(k),其中k < x呢?显然不是的,容易发现取2n的时候就得到了满足,

f(2n) = n*(2n+1) 此时对于f(2n)%n=0;

然后f(x)%n有对称性:f(x) = f(2n-1-x) (mod n)

很容易得到f(2n-1-x) = n(2n-x) -n(x+1) + x(x+1)/2 = f(x) (mod n)

那么是不是也存在类似于n为奇数情况的鸽巢原理之类的呢?

假设存在x,y满足f(x)=f(y)(mod n),其中x<y<n

f(y) - f(x) = (y-x)(y+x+1)/2 = 0 (mod n)

考虑等式(y-x)(y+x+1)=2nk,考虑k=1的时候,有(y-x)(y+x+1) = 2n

因为y-x=(y+x+1) (mod 2)2n可以被拆分成a*b的形式,根据因子分解得到,a,b中必然有一个是奇数。考虑a<ba为奇数,有y-x=a,y+x+1=b,所以x=(b-a-1)/2, y = (a+b-1)/2,也即形式:x = (2n/a-a-1)/2, y = (a+2n/a-1)/2,满足x<y<n,得到a>1,a<2n,特别的a=1的时候,n刚好是2^x的形式。其他情况下,均有解。

对于a>ba为奇数的情况,同样有a>1, a<2n,显然此时应该属于有解的情况

证毕

综上当n2^x形式时每个人都被发到糖果,否则肯定有人没有被发到糖果。特地缩行到96B。。。。。。

1 #include <stdio.h>
2 int main(){for(int n; scanf("%d", &n)!=EOF; puts(((n&(-n))==n)?"YES":"NO"));}
View Code