第二周 9.7---9.13

---------9.7

cf 575 h

http://codeforces.com/problemset/problem/575/H

题意不懂怎么描述诶,大意就是

先有一颗满二叉树,然后从根到叶子的路上有n条边染成红色,n条边染成蓝色,问满足这样条件的树有多少个节点

想到一点点,就是每次扩展下一层的时候,用本来应该满足满二叉树的节点数减去不合法的节点数---

可是不懂算这里------

本来按照一颗正常的二叉树

每扩展一层,节点数乘以2

但是因为有n的限制

就不会增加那么多个的节点

在前n层,是没有限制的,红色蓝色任意选

但是到第n+1层,因为肯定有两条路是已经填完红色,蓝色的

所以 它增加的节点数 为 (   C(n+1,n) - C(n,n) ) *2

然后假设现在走到深度为 K + 1

它比上一层增加的节点数 为 (C(K+1,n) - C(K,n))*2

再一层层的算

----------------话说不懂组合数取模,先抄了个lucas,T了

后来----抄了一个预处理的---------还是不懂这样算组合数---------------

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 const int MAXN = 2000010;
 9 const ll mod = 1e9 + 7;
10 
11 int N;
12 ll fac[MAXN + 10],afac[MAXN + 10];
13 
14 ll Q_pow(ll x,ll y){
15     ll res = 1;
16     x %= mod;
17     while(y){
18         if(y & 1) res = res * x % mod;
19         x = x * x % mod;
20         y >>= 1;
21     }
22     return res;
23 }
24 
25 void Pre(){
26     fac[0] = 1;
27     for(int i = 1; i <= MAXN; ++i) fac[i] = fac[i - 1] * (ll)i % mod;
28     afac[MAXN] = Q_pow(fac[MAXN],mod - 2);
29     for(int i = MAXN; i >= 1; --i) afac[i - 1] = afac[i] * i % mod;
30 }
31 
32 ll C(ll n,ll m){
33     if(m > n) return 0;
34     return fac[n] * afac[n - m] % mod * afac[m] % mod;
35 }
36 
37 int main(){
38     Pre();
39     scanf("%d",&N);
40     ll ans = Q_pow(2,N+1)-1;
41     ll cur = Q_pow(2,N);
42     ll tmp = cur;
43     for(int i = N+1;i <= 2*N;i++){
44         ll shao = 2LL*((C(i-1,N) - C(i-2,N) + mod) % mod) %mod;
45     //    printf("shao = %I64d\n",shao);
46         tmp = (tmp-shao + mod)%mod;
47          cur = cur + tmp;
48          ans = (ans + cur) %mod;
49          tmp = 2LL*tmp%mod;
50     }
51     printf("%I64d\n",ans);
52     return 0;
53 }
View Code

 

新的一周----加油--------------------------

 

cf 2B

http://codeforces.com/problemset/problem/2/B

这题目的编号 >_<

不会做------------

先想的是 dp[i][j]表示走到第i行,第j列的0最少有多少个

可是转移不出来

后来,题解是这样做的

因为答案所在的路径要不然是含有2的个数最少的,要不然是含有5的个数最少的

画几个例子就懂了---

然后就按照2的个数少dp一次,按照5的个数少dp一次

不过要注意给出的矩阵中本身含有0的情况

如果矩阵中含有0,就要用1和 dp2 ,dp5的答案去比较,1更小的话,直接构造出一条走0的路线

还是不懂路径打印----在cf上翻了一份------

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int INF = (1<<30)-1;
 8 const int maxn = 1005;
 9 int f[maxn][maxn][2],g[maxn][maxn][2];
10 int n,x,pos;
11 
12 void print(int x,int y){
13     if(x == 1 && y == 1) return;
14     if(g[x][y][pos]) print(x-1,y),printf("D");
15     else print(x,y-1),printf("R");
16 }
17 
18 int main(){
19     scanf("%d",&n);
20     memset(f,0,sizeof(f));
21     memset(g,0,sizeof(g));
22     
23     for(int i = 2;i <= n;i++) 
24     f[i][0][0] = f[i][0][1] = f[0][i][1] = f[0][i][0] = INF;
25     
26     for(int i = 1;i <= n;i++){
27         for(int j = 1;j <= n;j++){
28             int k;
29             scanf("%d",&k);
30             if(k == 0) x = i;
31             while(k){
32                 if(k%2 != 0) break;
33                 k = k/2;
34                 f[i][j][0]++;
35             }
36             while(k){
37                 if(k%5 != 0) break;
38                 k = k/5;
39                 f[i][j][1]++;
40             }
41             for(int k = 0;k < 2;k++){
42                 if(f[i-1][j][k] < f[i][j-1][k]) {
43                     f[i][j][k] += f[i-1][j][k];
44                     g[i][j][k] = 1;//D
45                 }
46                 else{
47                     f[i][j][k] += f[i][j-1][k];
48                     g[i][j][k] = 0;
49                 }
50             }
51         }
52     }
53     
54 //    for(int i = 1;i <= n;i++){
55 //        for(int j = 1;j <= n;j++){
56 //            for(int k = 1;k < 2;k++)
57 //            printf("f[%d][%d][%d] = %d  g[%d][%d][%d] = %d\n",i,j,k,f[i][j][k],i,j,k,g[i][j][k]);
58 //        }
59 //    }
60     
61     if(f[n][n][0] < f[n][n][1]) pos = 0;
62     else pos = 1;
63     
64     int ans = min(f[n][n][0],f[n][n][1]);
65     if(x && (ans > 1)){
66         puts("1");
67         for(int i = 2;i <= x;i++) printf("D");
68         for(int i = 2;i <= n;i++) printf("R");
69         for(int i = x+1;i <= n;i++) printf("D");
70     }
71     else{
72         printf("%d\n",ans);
73         print(n,n);
74     }
75     
76     return 0;
77 }
View Code

 

cf 463 d

http://codeforces.com/problemset/problem/463/D

求k个串的最长公共子序列

不懂做----

不过话说还是清醒的认识到----不能用第一个和第二个的最长公共子序列再去求第三个第四个的-------呜呜呜

应该这样---

如果对于一个数 i ,对于所有行的 j   ,i 的位置都比 j 的靠前,那么 i 到 j 连一条边

这样,就转化成了一个有向无环图,因为自己不可能连向自己

然后再求 DAG 上的最长路

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 1005;
 9 int n,k;
10 int a[maxn][maxn];
11 int pos[maxn][maxn];
12 vector<int> g[maxn];
13 int dp[maxn];
14 
15 //wei ziji jiayou >_<
16 
17 int dfs(int u){
18     if(dp[u]) return dp[u];
19     for(int i = 0;i < g[u].size();i++){
20         int v = g[u][i];
21         dp[u] = max(dp[u],dfs(v));
22     }
23     return dp[u] = dp[u] + 1;
24 }
25 
26 
27 int main(){
28     while(scanf("%d %d",&n,&k) != EOF){
29         memset(pos,0,sizeof(pos));
30         for(int i = 1;i <= n;i++) g[i].clear();
31         
32         for(int i = 1;i <= k;i++){
33             for(int j = 1;j <= n;j++){
34                 scanf("%d",&a[i][j]);
35                 pos[a[i][j]][i] = j;
36             }
37         }
38         
39         int ok = 1;
40         for(int i = 1;i <= n;i++){
41             for(int j = 1;j <= n;j++){
42                 ok = 1;
43                 for(int l = 1;l <= k;l++){
44                     if(pos[i][l] >= pos[j][l]){
45                         ok = 0;
46                         break;
47                     }
48                 }
49                 if(ok) g[i].push_back(j);
50             }
51         }
52         
53         int ans = -1;
54         memset(dp,0,sizeof(dp));
55         for(int i = 1;i <= n;i++) {
56             ans = max(ans,dfs(i));
57     //        printf("dp[%d] = %d  ans =%d\n",i,dp[i],ans);
58         }
59         printf("%d\n",ans);
60     }
61     return 0;
62 }
View Code

 

学KMP中----加上弄协会的事情----- 

哎--------------------------------------

加油拉

 

---------9.8

poj 3461 Oulipo

裸的KMP

因为做cf上的一道题目不会做---

搜题解发现好多用的是KMP

所以滚去学了一发

字符串第一位从1开始编号

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 10005;
 9 char a[100*maxn],b[maxn];
10 int p[maxn];
11 int lena,lenb;
12 
13 void Get_p(){
14     p[1] = 0;
15     int j = 0;
16     for(int i = 2;i <= lenb;i++){
17         while(j > 0 && b[j+1] != b[i]) j = p[j];
18         if(b[j+1] == b[i]) j++;
19         p[i] = j; 
20     }
21 }
22 
23 void KMP(){
24     Get_p();
25     int ans = 0;
26     int j = 0;
27     for(int i = 1;i <= lena;i++){
28         while(j > 0  && b[j+1] != a[i] ) j = p[j];
29         if(b[j+1] == a[i]) j++;
30         if(j == lenb){
31             j = p[j];
32             ans++;
33         }
34     }
35     printf("%d\n",ans);
36 }
37 
38 int main(){
39     int T;
40     scanf("%d",&T);
41     while(T--){
42         scanf("%s",b+1); lenb = strlen(b+1);
43         scanf("%s",a+1); lena = strlen(a+1);
44         
45         KMP();
46         
47         //for(int i = 1;i <= lenb;i++)
48         //printf("p[%d] = %d\n",i,p[i]);
49     }
50     return 0;
51 }
View Code

 补一个字符串从0开始编号的

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 10005;
 9 char a[100*maxn],b[maxn];
10 int p[maxn];
11 int lena,lenb;
12 
13 void Get_p(){
14     p[0] = -1;
15     int j = -1;
16     for(int i = 1;i < lenb;i++){
17         while(j >= 0 && b[j+1] != b[i]) j = p[j];
18         if(b[j+1] == b[i]) j++;
19         p[i] = j; 
20     }
21 }
22 
23 void KMP(){
24     Get_p();
25     int ans = 0;
26     int j = -1;
27     for(int i = 0;i < lena;i++){
28         while(j >= 0  && b[j+1] != a[i] ) j = p[j];
29         if(b[j+1] == a[i]) j++;
30         if(j == lenb-1){
31             j = p[j];
32             ans++;
33         }
34     }
35     printf("%d\n",ans);
36 }
37 
38 int main(){
39     int T;
40     scanf("%d",&T);
41     while(T--){
42         scanf("%s",b); lenb = strlen(b);
43         scanf("%s",a); lena = strlen(a);
44         
45         KMP();
46         
47         //for(int i = 1;i <= lenb;i++)
48         //printf("p[%d] = %d\n",i,p[i]);
49     }
50     return 0;
51 }
View Code

 

cf 404 c

http://codeforces.com/contest/404/problem/C

将高度排序,构造树的过程中记录下度数,就可以了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 int n,k;
 9 const int maxn = 100005;
10 int d[maxn];
11 int du[maxn];
12 vector<int> h[maxn];
13 vector<int> g[maxn];
14 
15 struct node{
16     int id;
17     int d;
18 }a[maxn];
19 
20 int cmp(node n1,node n2){
21     return n1.d < n2.d;
22 }
23 
24 void solve(){
25     sort(a+1,a+n+1,cmp);
26     
27     memset(du,0,sizeof(du));
28     int c = 0;
29     int root;
30     for(int i = 1;i <= n;i++){
31         if(a[i].d == 0) {
32             c++;
33             root = a[i].id;
34         } 
35     }
36     if(c == 0 || c > 1) {
37         puts("-1");
38         return;
39     }
40     
41     for(int i = 1;i <= n;i++){
42         h[a[i].d].push_back(a[i].id);
43     }
44     
45     for(int i = 2;i <= n;i++){
46         int l = a[i].d;
47         int r = a[i].id;
48         if(h[l-1].size() == 0){
49             puts("-1");
50             return;
51         }
52         int ok = 0;
53         for(int j = 0;j < h[l-1].size();j++){
54             int v = h[l-1][j];
55         //    printf("i = %d  v = %d  r = %d\n",i,v,r);
56             if(du[v] >= k) continue;
57             else{
58                 g[v].push_back(r);
59                 du[v]++;
60                 du[r]++;
61                 ok = 1;
62                 break;
63             }
64         }
65         if(ok == 0){
66             puts("-1");
67             return;
68         }
69     }
70     int res = 0;
71     for(int i = 1;i <= n;i++) res += g[i].size();
72     printf("%d\n",res);
73     for(int i = 1;i <= n;i++){
74         for(int j = 0;j < g[i].size();j++){
75             int v = g[i][j];
76             printf("%d %d\n",i,v);
77         }
78     }
79 }
80 
81 int main(){
82         scanf("%d %d",&n,&k);
83         for(int i = 1;i <= n;i++) g[i].clear(),h[i].clear();
84         
85         for(int i = 1;i <= n;i++) {
86             scanf("%d",&a[i].d);
87             a[i].id = i;
88         }
89         solve();
90     return 0;
91 }
View Code

话说做这题---有种页面找不到了的错觉------------->_<

 

话说做不来题目的时候,就画画,现在爪机里面攒了好多画了----还是觉得画得好的才拍照留下来-----

话说是有好多好多不会做的题目---------------------

该滚了---

哈哈哈哈---昨天买了速写本--决定做不来题目的时候就在本子上画画---------------------------------------------

加油加油加油

 

cf 505 c

http://codeforces.com/problemset/problem/505/C

好有缘分的两道题目~~~~

还是没有想出来啊---

想到的还是一维的,dp[i] 表示走到i的时候能够拿到的最多的宝石的数目,可是步数就不懂转移了

其实---是这样的-----

开二维的数组

dp[i][j]表示到达 i 的前一步跳了 j 步能够拿到的最多的宝石数

可是30000*3000就开不下了--

然后考虑相当于一直向某一个方向跳跃的情况

d-1, d-2,d-3,------,d-x

所以有 x*(x-1)/2 = 30000

解出来 x = 245

然后这样跳也是

d+1, d+2, d+3,------,d+x

x = 245

然后因为记忆化搜索的时候有要减去的情况(d-1,d-2-----d-245)

所以给它加上300或者400这些都可以

话说是这样理解得么~~~~~~~~~~~~~~~

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 int dp[30005][1000];
 8 int d,n,maxn;
 9 int a[30005];
10 
11 int dfs(int p,int pre){
12     if(p > maxn) return 0;
13     if(dp[p][pre-d+300] > -1) return dp[p][pre-d+300]; 
14     int res = 0;
15     if(pre > 1) res = max(res,dfs(p+pre-1,pre-1));
16     res = max(res,dfs(p+pre,pre));
17     res = max(res,dfs(p+pre+1,pre+1));
18     return dp[p][pre-d+300] = res + a[p];
19 }
20 
21 int main(){
22     memset(dp,-1,sizeof(dp));
23     memset(a,0,sizeof(a));
24     scanf("%d %d",&n,&d);
25     maxn = -1;
26     for(int i = 1;i <= n;i++){
27         int x;
28         scanf("%d",&x); maxn = max(maxn,x);
29         a[x]++;
30     }
31     printf("%d\n",dfs(d,d));
32     
33     return 0;
34 }
View Code

 

---------9.9

cf 126 b

http://codeforces.com/problemset/problem/126/B

KMPKMPKMPKMPKMP------

给出一个字符串,找出最长的子串,并且保证这个子串既是前缀,又是后缀,又在中间

没有想出来啊啊啊啊啊-----

最开始没有学KMP的时候---

是这样想的---

啊---我去二分一下后缀的起始端点,然后判断一下是否等于前缀还有中间是不是含有这个后缀就可以了--

nlogn---刚好----

可是---这个是没有单调性的,这一次的起始的端点不行,那下一次的端点在它的左边还是右边呢---不能确定---

所以不行----居然还过了10个样例------

然后--滚去学了一发KMP之后---

又愚蠢地这样想----

啊---去枚举一下前缀---看前缀在串里出现的次数是不是大于等于3,再维护合法的最长的前缀就好啦----

可是,,这样n^2  ,没有打

于是看题解了---------------------------------------------------------------------

发现还是p数组理解得不够好

可以写出有解的两种情况

1.

i         f   i   x   e   d   f   i   x   f   i   x

p[i]     0 0  0    0  0   1  2   3  1   2  3

不重合的三段

只要在前面找到一次p[n]就可以了

2. 

         p   a   p   a   p   a   p   a   p

p[i]   0    0   1   2   3   4   5   6   7

有重合的三段

1 ---5

2 ---7

3----9

如果p[p[n]] == 0就成不了三段,就没有解了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 1000005;
 9 char a[100*maxn],b[maxn];
10 int p[maxn];
11 int lena,lenb;
12 
13 //wei ziji jiayou >_<
14 
15 void Get_p(){
16     p[1] = 0;
17     int j = 0;
18     for(int i = 2;i <= lenb;i++){
19         while(j > 0 && b[j+1] != b[i]) j = p[j];
20         if(b[j+1] == b[i]) j++;
21         p[i] = j; 
22     }
23 }
24 
25 void solve(){
26     if(p[lenb] == 0){
27         puts("Just a legend");
28         return;
29     }
30     for(int i = 2;i < lenb;i++){
31     //    printf("p[%d] = %d  p[lenb] = %d\n",i,p[i],p[lenb]);
32         if(p[i] == p[lenb]){
33             for(int j = i-p[i]+1;j <= i;j++) printf("%c",b[j]);
34             printf("\n");
35             return;
36         }
37     }
38     
39     if(p[p[lenb]] == 0){
40         puts("Just a legend");
41         return;
42     }
43     for(int i = p[lenb]-p[p[lenb]]+1;i <= p[lenb];i++) printf("%c",b[i]);
44     printf("\n");
45 }
46 
47 int main(){
48     while(scanf("%s",b+1) != EOF){
49         memset(p,0,sizeof(p));
50         lenb = strlen(b+1);
51         Get_p();
52         
53         //for(int i = 1;i <= lenb;i++)
54         //printf("p[%d] = %d\n",i,p[i]);
55         solve();
56     }
57     return 0;
58 }
View Code

 

在下雨------

 

cf 107 a

http://codeforces.com/problemset/problem/107/A

从入度为0且没有访问过的点开始搜,维护每一条链的最小值

m等于0的时候,要输出0,而且必须是一条链,这条链上的点必须大于等于2个

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<vector>
  6 #define MP(a,b) make_pair(a,b)
  7 using namespace std;
  8 
  9 const int INF = (1<<30)-1;
 10 const int maxn = 1005;
 11 typedef pair<int,int> pii;
 12 vector<int> c[maxn];
 13 int first[maxn],ecnt;
 14 int n,m,cnt;
 15 int in[maxn],out[maxn],vis[maxn],w[maxn];
 16 
 17 struct Edge{ 
 18     int u,v,next,w;
 19 }e[maxn];
 20 
 21 struct node{
 22     int x,y,w;
 23 }ans[maxn];
 24 
 25 int cmp(node n1,node n2){
 26     return n1.x < n2.x;
 27 }
 28 
 29 void init(){
 30     ecnt = 0;
 31     memset(first,-1,sizeof(first));
 32 }
 33 
 34 void add_edges(int u,int v,int w){
 35     e[ecnt].u = u;
 36     e[ecnt].v = v;
 37     e[ecnt].w = w;
 38     e[ecnt].next = first[u];
 39     first[u] = ecnt++;
 40 }
 41 
 42 void dfs(int u){
 43     vis[u] = 1;
 44     if(in[u] == 0) ans[cnt].x = u;
 45     if(out[u] == 0) ans[cnt].y = u;
 46     for(int i = first[u];~i;i = e[i].next){
 47         int v = e[i].v;
 48         ans[cnt].w = min(ans[cnt].w,e[i].w);
 49         if(vis[v]) continue;
 50         dfs(v);
 51     }
 52 }
 53 
 54 void solve(){
 55     int c1 = 0;
 56     for(int i = 1;i <= n;i++){
 57         if(in[i] + out[i] == 2) c1++;
 58     }
 59     if(c1 == n || m == 0){
 60         puts("0");
 61         return;
 62     }
 63     
 64     
 65     memset(vis,0,sizeof(vis));
 66     for(int i = 1;i <= n;i++) ans[i].w = INF;
 67     
 68     cnt = 1;
 69     for(int i = 1;i <= n;i++){
 70         if(!vis[i] && in[i] == 0) dfs(i),cnt++;
 71     }
 72     
 73 //    for(int i = 1;i < cnt;i++){
 74 //        printf("a[%d].x = %d  a[%d].y = %d  a[%d].w = %d\n",i,ans[i].x,i,ans[i].y,i,ans[i].w);
 75 //    }
 76     
 77     sort(ans+1,ans+cnt,cmp);
 78     for(int i = 1;i < cnt;i++) if(ans[i].x == ans[i].y) cnt--;
 79     
 80     printf("%d\n",cnt-1);
 81     
 82     for(int i = 1;i < cnt;i++){
 83         printf("%d %d %d\n",ans[i].x,ans[i].y,ans[i].w);
 84     }
 85     
 86 }
 87 
 88 int main(){
 89     while(scanf("%d %d",&n,&m) != EOF){
 90         init();
 91         memset(in,0,sizeof(in));memset(out,0,sizeof(out));
 92         for(int i = 1;i <= m;i++){
 93             int u,v,w;
 94             scanf("%d %d %d",&u,&v,&w);
 95             out[u]++;in[v]++;
 96             add_edges(u,v,w);
 97         }
 98         solve();
 99     }
100     return 0;
101 }
View Code

 

cf 128 a

http://codeforces.com/contest/128/problem/A

外面国防生唱歌好带感啊---

我做题做得好忧郁啊---

bfs状态是三维的没想到

倒是把图按照时间弄成三维的,不知道咋想的,然后vis就标记不对啊,然后就一直跑啊-----飞一样的----

然后---wa4了---看数据还想不通为什么这个答案--(后来才发现是可以对角线走的)

于是看题解吧--

三维的bfs,vis再加一个时间就可以了---

然后写了一直wa10---

后来读题才发现,,,他还可以停留在原地----

不说了,桑心----555555555555555555555

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 
 8 char g[10][10];
 9 int vis[10][10][10];
10 int dir[9][2] = {0,0,1,0,1,1,0,1,-1,1,-1,0,-1,-1,0,-1,1,-1};
11 
12 struct node{
13     int x,y,t;
14 };
15 
16 int ok(int x,int y,int t){
17     if(x <= 0 || x > 8 || y <= 0 || y > 8 || g[x-t][y] == 'S') return 0;
18     return 1;
19 }
20 
21 bool bfs(){
22     memset(vis,0,sizeof(vis));
23     queue<node> q;
24     q.push(node{8,1,0});
25     
26     while(!q.empty()){
27         node u = q.front();q.pop();
28         
29         if(u.t > 8) return true;
30         if(g[u.x-u.t][u.y] == 'S') continue;
31         //printf("u.x = %d  u.y = %d  u.t = %d\n",u.x,u.y,u.t);
32         for(int i = 0;i < 9;i++){
33             int xx = u.x + dir[i][0];
34             int yy = u.y + dir[i][1];
35             if(!ok(xx,yy,u.t)) continue;
36             if(!vis[xx][yy][u.t+1]){
37                 vis[xx][yy][u.t+1] = 1;
38                 q.push(node{xx,yy,u.t+1});
39             }
40         }
41     }
42     return false;
43 }
44 
45 int main(){
46 //    freopen("in.txt","r",stdin);
47 //    freopen("out.txt","w",stdout);
48     for(int i = 1;i <= 8;i++){
49         for(int j = 1;j <= 8;j++){
50             cin >> g[i][j];
51         }
52     }
53     if(bfs()) puts("WIN");
54     else puts("LOSE");
55     return 0;
56 }
View Code

 

---------9.10

昨晚不想做题,看到别人博客有写生成树计数

于是滚去学了一下 >_<

给出一个无向图

它的度数矩阵记为 d[][]

当 i = j 的时候,d[i][j] 为 vi的度数

当 i != j 的时候,d[i][j]为0

它的邻接矩阵记为 a[][]

当i = j 的时候, a[i][j] = 0

当 i!= j的时候,如果i到j有边的话,a[i][j] = a[j][i] = 1

它的Kirchhoff矩阵等于 == d - a

然后无向图的生成树的个数为 它的Kirchhoff矩阵的任意 n-1 阶主子式的行列式绝对值

看证明没有看懂---------

抄一个模板

spoj 104

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 typedef long long LL;
 9 const int MAXN = 15;
10 LL g[MAXN][MAXN];
11 int n,m;
12 int d[MAXN];
13 
14 LL Det(LL A[MAXN][MAXN],int n){ 
15     LL res = 1;
16     for(int i = 1; i <= n; ++i){
17         for(int j = i + 1; j <= n; ++j){
18             while(A[j][i]){
19                 LL t = A[i][i] / A[j][i];
20                 for(int k = i; k <= n; ++k)
21                     A[i][k] = (A[i][k] - A[j][k] * t);
22                 for(int k = i; k <= n; ++k)
23                     swap(A[i][k],A[j][k]);
24                 res = -res; //行列式换行,值取反
25             }
26         }
27         if(!A[i][i]) return 0;
28         res = res * A[i][i] ;
29     }
30     if(res < 0) res = -res;
31     return res;
32 }
33 
34 int main(){
35     int T;
36     scanf("%d",&T);
37     while(T--){
38         memset(g,0,sizeof(g));
39         memset(d,0,sizeof(d));
40         scanf("%d %d",&n,&m);
41         for(int i = 1;i <= m;i++){
42             int u,v;
43             scanf("%d %d",&u,&v);
44             g[u][v] = g[v][u] = -1;
45             d[u]++;d[v]++;
46         }
47         for(int i = 1;i <= n;i++) g[i][i] = d[i];//g为原图的Kirchhoff矩阵 
48         printf("%lld\n",Det(g,n-1));//对矩阵g求一次n-1阶主子式的行列式绝对值 
49     }
50     return 0;
51 }
View Code

 

cf 518 d

http://codeforces.com/contest/518/problem/D

呜呜呜---第一次自己想出dp来,虽然是一道简单的概率dp,,,感动哭

加油---------

dp[i][j]表示第i秒有j个人的概率,然后递推的时候注意一下边界就可以了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 2005;
 9 double dp[maxn][maxn];
10 int n,t;
11 double p;
12 
13 int main(){
14     while(scanf("%d %lf %d",&n,&p,&t) != EOF){
15         memset(dp,0,sizeof(dp));
16         dp[1][0] = 1-p; dp[1][1] = p;
17         
18         for(int i = 2;i <= t;i++){
19             for(int j = 0;j <= n;j++){
20                 if(j > i) continue;
21                 if(j-1 >= 0) dp[i][j] += dp[i-1][j-1]*p;
22                 if(j == n) dp[i][j] += dp[i-1][j];
23                 if(j < n) dp[i][j] += dp[i-1][j]*(1-p);
24                 //printf("dp[%d][%d] = %lf\n",i,j,dp[i][j]);
25             }
26         }
27         double res = 0;
28         for(int i = 1;i <= n;i++) {
29             res += dp[t][i]*i;
30         //    printf("res = %lf\n",res);
31         }
32         printf("%lf\n",res);
33     }
34     return 0;
35 }
View Code

 

cf 219 d

给出一个有向图,可以修改边的方向,使得能够有点能够到达所有的其他点

问修改的最小的边的数量,并且输出满足这个条件的所有的点

 

想了好久,写了一个统计每个点包含点的个数的版本----wa4----

简直一点边都没有沾到----

 

应该是这样的http://www.cnblogs.com/Running-Time/p/4663538.html

搜的时候,标记顺着的方向,就是u ---> v的边权为0,逆着的方向的边权为1

(学习了,完全没有想到过这种,还在想,如果把它添加成双向的边,那就怎么搜都是0了,,,挫爆了---)

第一次dfs 以1为根,统计以1为根的时候需要修改的边数

第二次dfs,从上至下搜出每个节点分别需要修改的边数

最开始没有看懂---

后来用自己wa的那组数据画了一下,就好懂多了---

8
1 2
3 2
4 3
4 5
6 5
6 7
8 7

还搜到一篇言简意赅的题解----啊,说这个是很大众的树型dp----然后dfs一下下就好啦---

滚了----555555555555555
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 200005;
 9 int n,ecnt;
10 int first[maxn],vis[maxn],dp[maxn];
11 
12 struct Edge{
13     int u,v,w,next;
14 }e[2*maxn];
15 
16 void init(){
17     ecnt = 0;
18     memset(first,-1,sizeof(first));
19 }
20 
21 void add_edges(int u,int v,int w){
22     e[ecnt].u = u;
23     e[ecnt].v = v;
24     e[ecnt].w = w;
25     e[ecnt].next = first[u];
26     first[u] = ecnt++;
27 }
28 
29 void dfs1(int u){
30     vis[u] = 1;
31     for(int i = first[u];~i;i=e[i].next){
32         int v = e[i].v;
33         if(vis[v]) continue;
34         dfs1(v);
35         dp[1] += e[i].w;
36     }
37 }
38 
39 void dfs2(int u){
40     vis[u] = 1;
41     for(int i = first[u];~i;i=e[i].next){
42         int v = e[i].v;
43         if(vis[v]) continue;
44         if(e[i].w == 0) dp[v] = dp[u] + 1;
45         else dp[v] = dp[u]-1;
46         dfs2(v);
47     }
48 }
49 
50 void solve(){
51     memset(vis,0,sizeof(vis));
52     memset(dp,0,sizeof(dp));
53     dfs1(1);
54 //    printf("dp[1] = %d\n",dp[1]);
55     memset(vis,0,sizeof(vis));
56     dfs2(1);
57 //    for(int i = 1;i <= n;i++) printf("dp[%d] = %d\n",i,dp[i]);
58     
59     int minn = (1<<30)-1;
60     for(int i = 1;i <= n;i++) minn = min(minn,dp[i]);
61     
62     printf("%d\n",minn);
63     for(int i = 1;i <= n;i++) if(dp[i] == minn)printf("%d ",i);
64     printf("\n");
65 }
66 
67 int main(){
68     while(scanf("%d",&n) != EOF){
69         init();
70         for(int i = 1;i <= n-1;i++){
71             int u,v;
72             scanf("%d %d",&u,&v);
73             add_edges(u,v,0);
74             add_edges(v,u,1);
75         }
76         solve();
77     }
78     return 0;
79 }
View Code

 

---------9.11

cf 577 b

http://codeforces.com/problemset/problem/577/B

补昨晚的cf

话说这一题真是坎坷--

先wa10,后来没有考虑对,状态好不容易推出来,边界又不对--

最后看了别人的代码改,才过,还不懂鸽巢原理那一块儿的证明

 

给出n个数(n<= 1000000),再给出m, 问能不能够从这n个数里面选择一些数出来,使得它们的和为m的倍数

 

第一反应就是挑战上面的dp有讲过, 可是n太大了   (可是m很小,用了鸽巢定理)

然后,自己考虑的不对的地方在于,没有想到对a[i] % m,还想着去枚举m的倍数

然后另外,就是取模之后,判断是不是能够的时候,应该是判断 dp[n][0],我想的是判断dp[n][m](真是被自己打败,明明都对m取余了的说)

然后,状态写出来之后,也一直写不对,是因为边界没有搞好----

 

还有 n > m的情况,所有前缀和mod m后必定有两个前缀和相等。然后中间那段的数的和mod m=0

这个还不懂证明,搞懂了再来补上吧 >_< 

加油 *>_<*

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<set>
 6 using namespace std;
 7 
 8 const int maxn = 1000005;
 9 int dp[1005][1005];
10 int n,m;
11 int a[maxn];
12 
13 void solve(){
14     if(n <= m){
15         memset(dp,0,sizeof(dp));
16         for(int i = 1;i <= n;i++) dp[i][a[i]] = 1;
17         for(int i = 2;i <= n;i++){
18             for(int j = 0;j < m;j++){
19              dp[i][j] |= dp[i-1][j];
20              dp[i][j] |= dp[i-1][(j-a[i]+m)%m];
21         //     printf("dp[%d][%d] = %d\n",i,j,dp[i][j]);
22             }
23         }
24         if(dp[n][0]) puts("YES");
25         else puts("NO");
26     }
27     else{
28         set<int> s;
29         int sum = 0;
30         for(int i = 1;i <= n;i++){
31             sum = (sum+a[i])%m;
32             if(s.find(sum) != s.end()){
33                 puts("YES");
34                 return;
35             }
36             s.insert(sum);
37         }
38         puts("NO");
39     }
40 }
41 
42 int main(){
43     while(scanf("%d %d",&n,&m) != EOF){
44         memset(a,0,sizeof(a));
45         for(int i = 1;i <= n;i++) scanf("%d",&a[i]),a[i] = a[i]%m;
46         solve();
47     }
48     return 0;
49 }
View Code

 

---------9.12

其实是今天(9.13)写的--

早上YY了一下cf的那个E题,

各种排序---最后以为再改改就对了--发现少看了两个0,数量级都不对嘛-----

搜题解,说是分块---

待补---

协会纳新中--->_<感觉是我们协会的唠嗑大会

晚上做了bc

还没有补题

-------------------------------------

 

---------9.13

大家一起做了长春的网络赛

好残暴啊---

至少过7题才能进---

真是----------------唉,没事,加油

加油

hdu  5441

给出一个图,q个查询,查询a到b满足每条边的权值小于等于x的 点对 (a,b)

用并查集,将询问排个序,再将边排个序,依次添加合法的进去

 

下午比完赛,睡了一觉起来就敲

一会儿就敲完了,可是一直wa

后来---

才知道是输出记录编号那里错了,因为样例就是顺着的,怎么记录都是对的--

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 typedef long long LL;
 9 const int maxn = 20005;
10 
11 struct Edge{
12     int u,v,d;
13 }e[10*maxn];
14 
15 int cmp1(Edge e1,Edge e2){
16     return e1.d < e2.d;
17 }
18 
19 struct node{
20     int l,id;
21 }q[maxn];
22 
23 int cmp2(node n1,node n2){
24     return n1.l < n2.l;
25 }
26 
27 int n,m,Q;
28 
29 int p[maxn],sz[maxn];
30 LL res[maxn];
31 
32 int find(int x){return x == p[x] ? x :p[x] = find(p[x]);}
33 
34 void Union(int u,int v){
35     int x = find(u);
36     int y = find(v);
37     if(sz[x] >= sz[y]){
38         p[y] = x;
39         sz[x] += sz[y];
40     }
41     else{
42         p[x] = y;
43         sz[y] += sz[x];
44     }    
45 }
46 
47 int main(){
48     int T;
49     scanf("%d",&T);
50     while(T--){
51         memset(res,0,sizeof(res));
52         scanf("%d %d %d",&n,&m,&Q);
53         for(int i = 1;i <= m;i++){
54             scanf("%d %d %d",&e[i].u,&e[i].v,&e[i].d);
55         }
56         for(int i = 1;i <= Q;i++){
57             scanf("%d",&q[i].l);
58             q[i].id = i;
59         }
60         
61         for(int i = 1;i <= n;i++) p[i] = i,sz[i] = 1;
62         sort(e+1,e+m+1,cmp1);
63         sort(q+1,q+Q+1,cmp2);
64         
65         int pos = 1;
66         LL ans = 0;
67         for(int i = 1;i <= Q;i++){
68             for(;pos <= m && e[pos].d <= q[i].l;pos++){
69                 int u = e[pos].u;
70                 int v = e[pos].v;
71                 int x = find(u);
72                 int y = find(v);
73                 if(x != y) {
74                     ans += sz[x] *sz[y]*2;
75                     Union(u,v);
76                 }
77             }
78             res[q[i].id] = ans;
79         }
80     
81         for(int i = 1;i <= Q;i++){
82             printf("%I64d\n",res[i]);
83         }
84     }
85     return 0;
86 }
View Code

 

转载于:https://www.cnblogs.com/wuyuewoniu/p/4788637.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值