第六周 8.23---8.30

以后每周写一篇了吧~~

暑假集训就这样结束了的说----

话说起来,还是什么都不会啊----

能够想起来的,就是这一个月,

每周二,多校,周三,补题,周四,多校,剩下,补题-----

感觉自己补题很吃力,有时候半天一天搞懂一道题,有时候还不能自己敲出来--

学了点连通分量,只会模板题,学了一点网络流,可是做的题太少,根本不会建图- -

感觉没有长进----

这种时候~~~又翻翻火影,打打鸡血啊什么的~~~又想到自来也~~

又充满能量~~~goooooooooooooo

那就一步一步的来吧,那就一道题一道题的去做吧,那就一个算法一个算法的去学吧~~~

把今后的每一天,当成对自己的承诺,加油加油~~~gooooooooo~~

---------8.23

补bc

不会状压dp,晚上滚回去补吧~~

cf 300 b

用并查集统计一下每个连通块里面的点的个数,不够3的凑一下

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<iostream>
  5 #include<vector>
  6 using namespace std;
  7 
  8 int p[105];
  9 int n,m,N;
 10 int vis[105];
 11 
 12 int find(int x){ return x == p[x] ? x : p[x] = find(p[x]);}
 13 
 14 void solve(){
 15     vector<int> ans[105];
 16     if(m == 0){
 17         for(int i = 1;i <= n;i += 3){
 18             for(int j = i;j < i+3;j++)
 19             printf("%d ",j);
 20             printf("\n");
 21         }
 22         return;
 23     }
 24     
 25     for(int i = 1;i <= n;i++){
 26         int root = find(i);
 27         ans[root].push_back(i);
 28     }
 29     
 30     int c1 = 0,c2 = 0;
 31     for(int i = 1;i <= n;i++){
 32         if(ans[i].size() == 0) continue;
 33         if(ans[i].size() > 3) {
 34             puts("-1");
 35             return;
 36         }
 37         if(ans[i].size() == 1) c1++;
 38         if(ans[i].size() == 2) c2++;
 39     }
 40     
 41     if(c1 == 0 && c2 == 0){
 42         for(int i = 1;i <= n;i++){
 43             if(ans[i].size() != 0) printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
 44         }
 45         return;
 46     }
 47     else{
 48         if((c1 < c2) || (c1-c2) % 3 != 0) {
 49             puts("-1");
 50             return;
 51         }
 52         int cnt = 0;
 53         vector<int> res[105];
 54         for(int i = 1;i <= n;i++){
 55             if(ans[i].size() == 2 && !vis[i]){
 56                 vis[i] = 1;
 57                 for(int j = 1;j <= n;j++){
 58                     if(ans[j].size() == 1 && !vis[j]){
 59                     //    printf("--- i = %d  j = %d\n",i,j);
 60                         vis[j] = 1;
 61                         res[cnt].push_back(ans[j][0]);
 62                         res[cnt].push_back(ans[i][0]);
 63                         res[cnt++].push_back(ans[i][1]);
 64                         break;
 65                     }
 66                 }
 67             }
 68         }
 69         
 70         if((c1 > c2)){
 71             int ok = 0;
 72         //    printf("c1 = %d  c2 = %d\n",c1,c2);
 73             for(int i = 1;i <= n;i++){
 74                 ok = 0;
 75             if(ans[i].size() == 1 && !vis[i]){
 76                 vis[i] = 1;
 77                 for(int j = 1;j <= n;j++){
 78                     if(ans[j].size() == 1 && !vis[j]){
 79                         vis[j] = 1;
 80                         for(int k = 1;k <= n;k++){
 81                             if(ans[k].size() == 1 && !vis[k]){
 82                                 vis[k] = 1;
 83                                 res[cnt].push_back(ans[i][0]);
 84                                 res[cnt].push_back(ans[j][0]);
 85                                 res[cnt++].push_back(ans[k][0]);
 86                                 ok = 1;
 87                             }
 88                             if(ok) break;
 89                         }
 90                     }
 91                     if(ok) break;
 92                 }
 93             }
 94            }        
 95         }
 96 
 97         for(int i = 1;i <= n;i++) {
 98             if(ans[i].size() == 3) printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);
 99         }
100         for(int i = 0;i < cnt;i++) printf("%d %d %d\n",res[i][0],res[i][1],res[i][2]);    
101     }
102 }
103 
104 int main(){
105     while(scanf("%d %d",&n,&m) != EOF){
106         for(int i = 1;i <= n;i++) p[i] = i;
107         for(int i = 1;i <= m;i++){
108             int u,v;
109             scanf("%d %d",&u,&v);
110             int x = find(u);
111             int y = find(v);
112             if(x != y) p[x] =y;
113         }
114         
115         memset(vis,0,sizeof(vis));
116         solve();
117     }
118     return 0;
119 }
View Code

 

cf 466 c 

标签是dp---于是一直想状态,憋一天也没有憋出来------

可耻的看了题解

先算出每一段的和 x = sum[n]/3;

然后扫一遍,碰到sum[i] == x的,计数cnt++;

碰到sum[i] == 2*x的,说明前面已经有两段了,所以 ans += cnt;

 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 = 500005;
 9 LL sum[maxn],a[maxn];
10 int n;
11 
12 void solve(){
13     if(sum[n] % 3 != 0){
14         puts("0");
15         return ;
16     }
17     LL x = sum[n]/3;
18     LL cnt = 0;
19     LL ans = 0;
20     for(int i = 1;i < n;i++){    
21         if(i != 1 && sum[i] == 2*x) {
22             ans += cnt;
23         //    printf("i = %d  ans = %I64d\n",i,ans);
24         }
25         if(sum[i] == x) {
26             cnt++;
27         //    printf("i = %d  cnt = %d\n",i,cnt);
28         }
29     }
30     printf("%I64d\n",ans);
31 }
32 
33 int main(){
34     while(scanf("%d",&n) != EOF){
35         for(int i = 1;i <= n;i++) scanf("%I64d",&a[i]);
36         memset(sum,0,sizeof(sum));
37         for(int i = 1;i <= n;i++) sum[i] = sum[i-1] + a[i];
38         solve();
39     }
40     return 0;
41 }
View Code

 

cf 414 b

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

~~~只想出了状态,可是不懂转移啊~不对,还想出了初始化~~~~呜呜呜呜~~弱成狗~~

dp[i][j]表示长度为i,以j为结尾的方案数

 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 mod = 1e9 + 7;
 9 int dp[2005][2005];
10 int n,k;
11 
12 int main(){
13     while(scanf("%d %d",&n,&k) != EOF){
14         memset(dp,0,sizeof(dp));
15         for(int j = 1;j <= n;j++) dp[1][j] = 1;
16         
17         for(int i = 1;i < k;i++){
18             for(int j = 1;j <= n;j++){
19                 for(int l = j;l <= n;l+=j){
20                     dp[i+1][l] = (dp[i+1][l] + dp[i][j]) % mod;
21                 //    printf("dp[%d][%d] = %d\n",i+1,l,dp[i+1][l]);
22                 }
23             }
24         }
25         LL res = 0;
26         for(int j = 1;j <= n;j++) res = (res + dp[k][j]) % mod;
27         printf("%I64d\n",res);
28     }
29     return 0;
30 }
View Code

 

cf 166 e

终于自己想出一下公式来~~~虽然因为爆int  wa了一发~~

a[i] = 2*a[i-1] + 3*a[i-2]

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int mod = 1e9 + 7;
 8 long long  a[10000005];
 9 
10 int main(){
11     a[2] = 3;
12     a[3] = 6;
13     for(int i = 3;i <= 10000005;i++) a[i] = (2*a[i-1] + 3*a[i-2]) % mod;
14     int n;
15     while(scanf("%d",&n) != EOF){
16         printf("%I64d\n",a[n]);
17     }
18     return 0;
19 }
View Code

 

---------8.24

cf 431 c

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

这题也想好久---不过还是没有想出来的说,,,

然后搜了一篇题解,定义状态为dp[i][j][k]为当前在第i层,和为j,最大值为j的方案数,

这个的转移也好懂,只是因为初始化得和他不一样,一直推不出答案来

不明白它为什么初始化为dp[i][i][i] = 1,第i层和为i且最大值也为i不应该除了第一层,其余的都不满足了么-----

实在不懂了---

 

然后看的cf上面的题解----又是看好久----捉----急-----

dp[n][0]表示路径的权值和为n,不含有长度至少为d的边

dp[n][1]表示路径的权值和为n,还有长度至少为d的边

因为n可以看成是 (n-1)+ 1,(n-2) + 2,(n-3) + 3, (n-DL) + DL,其中DL = d-1

所以

dp[n][0] = dp[n-1][0] + dp[n-2][0] + dp[n-3][0] +-----+ dp[n-DL][0]

然后

dp[n][1]有两种情况

新加入的边的权值刚好大于d,dp[i][1] += dp[i-j][0]

以前就已经满足了有边的权值大于d,dp[i][1] += dp[i-j][1]

不知道理解得对不对的说-------

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int mod = 1e9 + 7;
 8 typedef long long LL;
 9 LL dp[105][2];
10 int n,k,d;
11 
12 void add(LL& a,LL b){
13     a += b;
14     if(a > mod) a -= mod;
15 }
16 
17 int main(){
18     while(scanf("%d %d %d",&n,&k,&d) != EOF){
19         memset(dp,0,sizeof(dp));
20         dp[0][0] = 1;
21         dp[0][1] = 0;
22         
23         for(int i = 1;i <= n;i++){
24             for(int j = 1;j <= k;j ++){
25                 if(i < j) continue;
26                 if(j < d) {
27                     add(dp[i][0],dp[i-j][0]);
28                     add(dp[i][1],dp[i-j][1]);
29                 }
30                 else{
31                     add(dp[i][1],dp[i-j][0]);
32                     add(dp[i][1],dp[i-j][1]);
33                 }
34             }
35         }
36         printf("%I64d\n",dp[n][1]);
37     }
38     return 0;
39 }
View Code

 

后来下午问了下wtw----,讨论了几下下,,,终于懂了上午的题解,可以不用开三维的数组

dp[i][j]表示和为i,最大值为j的方案数

还遭遇了因为数组越界---打印出中间值结果就对----不打印就不对的---------------------------------好醒觉啊~~~~

 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 mod = 1e9 + 7;
 9 LL dp[105][105];
10 int n,k,d;
11 
12 int main(){
13     while(scanf("%d %d %d",&n,&k,&d) != EOF){
14         memset(dp,0,sizeof(dp));
15         for(int i = 1;i <= n;i++) dp[i][i] = 1;
16         
17         for(int i = 2;i <= n;i++){
18             for(int j = 1;j <= k;j++){
19                 if(i < j) continue;
20                 for(int l = 1;l <= j;l++){
21                     dp[i][j] += dp[i-l][j];
22                 //    printf("----dp[%d][%d] = %d\n",i,j,dp[i][j]);
23                     if(dp[i][j] > mod) dp[i][j] -= mod;
24                 //    printf("dp[%d][%d] = %d\n",i,j,dp[i][j]);
25                 }
26                 for(int l = j+1;l <= k;l++){
27                     if(i < l) continue;
28                     dp[i][l] += dp[i-l][j];
29                 //    printf("===dp[%d][%d] = %d\n",i,l,dp[i][l]);
30                     if(dp[i][l] > mod) dp[i][l] -= mod;
31                 //    printf("dp[%d][%d] = %d\n",i,l,dp[i][l]);
32                 }    
33             }
34         }
35         LL res = 0;
36         for(int i = d;i <= k;i++) {
37             res += dp[n][i];
38             if(res > mod) res -= mod;
39         }
40         printf("%I64d\n",res);
41     }
42     return 0;
43 }
View Code

 

cf 467 c

dp[i][j]表示从前i个数里面选出j对的最大值

哎----只想出了状态----没有想出转移----

继续加油------------------------------------------

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

 

cf 103 b

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

最开始没有读懂题---后来读懂题了----找环

一棵树有环的话,点数等于边数,再判断这个给出的图是不是连通的

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 vector<int> g[105];
 9 int n,m;
10 int vis[105];
11 
12 void dfs(int u){
13     vis[u] = 1;
14     for(int i = 0;i < g[u].size();i++){
15         int v = g[u][i];
16         if(!vis[v]) dfs(v);
17     }
18 }
19 
20 int solve(){
21     if(n != m) return 0;
22     
23     int cnt = 0;
24     for(int i = 1;i <= n;i++){
25         if(!vis[i]) {
26             dfs(i);
27             cnt++;
28         }
29     }
30     return cnt == 1;
31 }
32 
33 int main(){
34     while(scanf("%d %d",&n,&m) != EOF){
35         for(int i = 1;i <= n;i++) g[i].clear();
36         memset(vis,0,sizeof(vis));
37         
38         for(int i = 1;i <= m;i++){
39             int u,v;
40             scanf("%d %d",&u,&v);
41             g[u].push_back(v);
42             g[v].push_back(u);
43         }
44         if(solve()) puts("FHTAGN!");
45         else puts("NO");
46     }
47     return 0;
48 }
View Code

 

---------8.25

 

cf 339 c

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

标签是dfs,可是不会搜---一会儿再想想怎么写---

于是贪心了----

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 char s[15];
 9 int a[15];
10 int m;
11 
12 void solve(){
13     sort(a+1,a+11);
14     int lb = 0,ub = 0;
15     vector<int> ans;
16     int first = 1;
17     int ji = 0,ou = 0;
18     
19     for(int j = 1;j <= 10;j++){
20         if(a[j] == 0) continue;
21         ji = 0; ou = 0;first = 0; ji += a[j];
22         lb = 0; ub = 0;
23     //    printf("j = %d  ji = %d\n",j,ji);
24         ans.clear();
25         ans.push_back(a[j]);
26         for(int k = 1;k <= m-1;k++){
27             if(first){
28                 for(int i = 1;i <= 10;i++){
29                     if(a[i] + ji > ou && a[i] != a[ub]){
30                         ji += a[i];
31                         lb = i;
32                     //    printf("j = %d  lb = %d\n",j,lb);
33                         ans.push_back(a[i]);
34                         first = !first;
35                         break;
36                     }
37                 }
38             }
39             else{
40                 for(int i = 1;i <= 10;i++){
41                     if(a[i] + ou > ji && a[i] != a[lb]){
42                         ou += a[i];
43                         ub = i;
44                     //    printf("j = %d  ub = %d\n",j,ub);
45                         ans.push_back(a[i]);
46                         first = !first;
47                         break;
48                     }
49                 }    
50             }    
51         }
52     //    printf("j = %d  ans.size() = %d\n",j,ans.size());
53         if(ans.size() == m){
54             puts("YES");
55             for(int i = 0;i < ans.size();i++)
56             printf("%d ",ans[i]);
57             printf("\n");
58             return;
59         }
60     }
61     
62     puts("NO");
63 }
64 
65 int main(){
66     while(scanf("%s",s+1) != EOF){
67         scanf("%d",&m);
68         for(int i = 1;i <= 10;i++){
69             if(s[i] == '1') a[i] = i;
70             else a[i] = 0;
71         }
72         a[0] = 0;
73         solve();
74     }
75     return 0;
76 }
View Code

 

补上搜索的----

自己写的搜索还是不对,,条理还是不够清晰吧----

木事---加油---

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 char s[15];
 9 int w[15];
10 int m,n;
11 int ans[1005];
12 
13 int dfs(int ji,int ou,int pre,int k,int op){
14     if(k == m+1) return true;
15     int tmp = 0;
16     if(op == 0){
17         for(int i = 1;i <= n;i++){
18             tmp = w[i] + ji;
19             //printf("---tmp = %d pre = %d\n",tmp,pre);
20             
21             if(tmp > ou && w[i] != pre){
22                 ans[k] = w[i];
23                 if(dfs(tmp,ou,w[i],k+1,!op)) return true;
24             }
25         }
26     }
27     else{
28         for(int i = 1;i <= n;i++){
29             tmp = w[i] + ou;
30             //printf("===tmp = %d  pre = %d   r\n",tmp,pre);
31             
32             if(tmp > ji && w[i] != pre){
33                 ans[k] = w[i];
34                 if(dfs(ji,tmp,w[i],k+1,!op)) return true;
35             }
36         }    
37     }
38     return false;
39 }
40 
41 int main(){
42     while(scanf("%s",s+1) != EOF){
43         n = 0;
44         for(int i = 1;i <= 10;i++) if(s[i] == '1') w[++n] = i;
45         
46         scanf("%d",&m);
47         memset(ans,0,sizeof(ans));
48         if(dfs(0,0,-1,1,0)){
49             puts("YES");
50             for(int i = 1;i <= m;i++) printf("%d ",ans[i]);
51             puts("");
52         }
53         else puts("NO");
54     }
55     return 0;
56 }
View Code

 

 

 

 

----------------停电---断网---中-------------

花店橱窗布置

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 int dp[105][105];
 9 int a[105][105];
10 int b[105][105];
11 int c[105];
12 int f,v;
13 
14 int main(){
15 //    freopen("in.txt","r",stdin);
16 //    freopen("out.txt","w",stdout);
17     scanf("%d %d",&f,&v);
18     memset(dp,0,sizeof(dp));
19     memset(a,0,sizeof(a));
20     memset(b,0,sizeof(b));
21     
22     for(int i = 1;i <= f;i++)
23         for(int j = 1;j <= v;j++) scanf("%d",&a[i][j]);
24     
25     for(int i = 1;i <= f;i++)  dp[i][i] = dp[i-1][i-1] + a[i][i],b[i][i] = 1;
26     
27     for(int i = 1;i <= f;i++){
28         for(int j = 1;j <= v;j++){
29             if(j <= i) continue;
30             b[i][j] = dp[i-1][j-1] + a[i][j] > dp[i][j-1];
31             
32             if(b[i][j]) dp[i][j] = dp[i-1][j-1] + a[i][j];
33             else dp[i][j] = dp[i][j-1];
34             
35         //    printf("dp[%d][%d] = %d\n",i,j,dp[i][j]);
36         }
37     }
38     printf("%d\n",dp[f][v]);
39     
40     int j = f;
41     for(int i = v;i >= 1;i--){
42         if(b[j][i]) {
43             c[j] = i;
44             //printf("----- j = %d  i = %d\n",j,i);
45             j--;
46         }
47     }
48     
49     for(int i = 1;i < f;i++) printf("%d ",c[i]);
50     printf("%d\n",c[f]);
51     
52     return 0;
53 }
View Code

 

---------8.26

 

cf 553 a

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

给出k种颜色,每一种颜色对应有c[i]个物品,要求第i种颜色的最后一个物品出现在第i-1种颜色的最后一个物品之后,求放置的方案数

往可重集合排列那边去想了----样例都算不对- -

后来看了题解

考虑第i种颜色,只需要留最后一个物品放在最后,那么前面该种颜色的另外 c[i] - 1 个可以随意放

转化成 求C(sum[i-1] + c[i]-1,c[i]-1)

最开始一直想不通这个公式,隔板法和插空法学得不懂-----------

后来看这篇---

http://lowsfish.com/?p=173

 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 mod = 1e9 + 7;
 9 int d[1005];
10 int sum[1005];
11 LL f[1005];
12 LL c[1010][1010];
13 int k;
14 
15 void init(int n,int m)
16 {
17     int  i,j;
18     memset(c,0,sizeof(c));
19     for(i=0;i<=m;i++) c[0][i]=c[1][i]=1;
20     for(i=0;i<=m;i++) c[i][i]=1;
21     for(i=0;i<=n;i++) c[i][0]=1;
22     for(i=1;i<=n;i++){
23         for(j=1;j<=m;j++){
24             if(i!=j)
25             c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
26         }
27     }
28 }
29 
30 
31 int main(){
32     init(1005,1005);
33     while(scanf("%d",&k) != EOF){
34         memset(sum,0,sizeof(sum));
35         for(int i = 1;i <= k;i++) {
36             scanf("%d",&d[i]);
37             sum[i] = sum[i-1] + d[i];
38         }
39         f[1] = 1;
40         for(int i = 2;i <= k;i++){
41             f[i] = (f[i-1] * c[sum[i-1] + d[i] - 1][d[i]-1])% mod;
42         //    printf("f[%d] = %I64d\n",i,f[i]);
43         }
44         printf("%I64d\n",f[k]);
45     }
46     return 0;
47 }
View Code

 

cf 289 b

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

dp的标签,可是不懂dp怎么做----

贪心写的--

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 
 8 int n,m,d;
 9 int a[105*105];
10 int cnt ;
11 
12 void solve(){
13     sort(a,a+cnt);
14     int lb,ub;
15     int ans = 0;
16     if(cnt % 2 == 1) {
17         ub = a[cnt/2];
18         for(int i = 0;i < cnt;i++){
19             int x = abs(a[i] - ub);
20             if(x % d){
21                 puts("-1");
22                 return;
23             }
24             ans += x / d;
25         }
26     }
27     else{
28         int c1 = 0,c2 = 0;
29         lb = a[cnt/2-1],ub = a[cnt/2];
30         for(int i = 0;i < cnt;i++){
31             int x = abs(a[i] - lb);
32             if(x % d){
33                 puts("-1");
34                 return;
35             }
36             c1 += x / d;
37         }
38         
39         for(int i = 0;i < cnt;i++){
40             int x = abs(a[i] - ub);
41             if(x % d){
42                 puts("-1");
43                 return;
44             }
45             c2 += x / d;
46         }
47         ans = min(c1,c2);
48     }
49     printf("%d\n",ans);
50 }
51 
52 int main(){
53     while(scanf("%d %d %d",&n,&m,&d) != EOF){
54         cnt = 0;
55         memset(a,0,sizeof(a));
56         
57         for(int i = 1;i <= n;i++){
58             for(int j = 1;j <= m;j++){
59                 scanf("%d",&a[cnt++]);
60             }
61         }
62         solve();
63     }
64     return 0;
65 }
View Code

 

hdu 5419

给出n个数,w[1],w[2],---到w[n]

再给出m个区间,从这m个区间里面任意选择三个区间出来,求这三个区间的并的和的期望

先是没有思路的,后来看了题解,不懂差分前缀和----

后来请教了别人------终于懂一点点了

首先分母是 C(m,3)

然后考虑每个数的贡献就是会有多少种组合会覆盖到它,因为可以选择的方式有很多种,所以这个不好算

然后可以假设一个数被x个区间覆盖,那么这个数的贡献就是 C(x,3)

比如说现在一个数被 4 个区间覆盖了,这四个区间的编号是 1 2 3 4

可以选择的方案有

1 2 3

1 2 4

1 3 4

2 3 4

4 种

所以贡献是 C(4,3),,,所以每个数的贡献是C(x,3)

然后再求每个数被覆盖了多少次

如果用这样的 for(int i = l;i <= r;i++) cover[i]++;

复杂度是 O(nm) 会T掉---

 

假设现在有一个区间是 [3,6]

 A   1 2 3 4 5 6 7 8

      0 0 1 1 1 1 0 0

定义 B数组为 B[i] = A[i] - A[i-1] (就像是对A序列求导一样)

B   1 2 3 4 5 6  7  8

      0 0 1 0 0 0 -1 0

因为 A ' = B

所以 对 B 求定积分等于A

再求B的前缀和发现还原成数组A了

B的前缀和   1 2 3 4 5 6 7 8

                 0 0 1 1 1 1 0 0

这样一个区间就只变成了两个有用的值,b[left],b[right]

所以就是,先差分,再求前缀和

把m个区间的b累加起来,就可以求出每个位置的贡献

 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 = 50005;
10 int w[maxn];
11 int b[maxn],s[maxn];
12 int n,m;
13 
14 LL C(int x){
15     if(x < 3) return 0;
16     LL ans = (LL)x *(LL) (x-1) * (LL)(x-2);
17     return ans/6;
18 }
19 
20 LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); }
21 
22 int main(){
23     int T;
24     scanf("%d",&T);
25     while(T--){
26         scanf("%d %d",&n,&m);
27         for(int i = 1;i <= n;i++) scanf("%d",&w[i]);
28         
29         memset(b,0,sizeof(b));
30         for(int i = 1;i <= m;i++){
31             int l,r;
32             scanf("%d %d",&l,&r);
33             b[l] += 1;b[r+1] -= 1;
34         }
35         
36         memset(s,0,sizeof(s));
37         for(int i = 1;i <= n;i++) s[i] += s[i-1] + b[i];
38         
39         
40         LL c1 = 0;
41         for(int i = 1;i <= n;i++){
42             c1 += 1LL * w[i] * C(s[i]);    
43         }
44         if(c1 == 0) {printf("%I64d\n",c1);continue;}
45         
46         LL c2 = C(m);
47         LL g = gcd(c1,c2);
48         c1 = c1/g; c2 = c2/g;
49         if(c2 == 1) printf("%I64d\n",c1);
50         else printf("%I64d/%I64d\n",c1,c2);
51     }
52     return 0;
53 }
View Code

 

搜题解看到有线段树区间更新写的,,不懂-------

 

cf 546 d

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

 求[a,b] 素因子的个数

第一次做是5月份,不会----

过了三个月---咦--发现多校不是做过一道像这样的题目么,统计一下每个数由多少种素数组成----

,,,,不过话说是求个数的啊---

还是不懂写------看了别人的代码----

记录下组成每个数的最大的素因子,就可以倒着找回去了

 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 = 5000005;
 9 LL res[maxn];
10 int p[maxn],b[maxn];
11 
12 void init(){
13     memset(p,0,sizeof(p));
14     memset(b,0,sizeof(b));
15     memset(res,0,sizeof(res));
16     
17     p[0] = 0; p[1] = 1;
18     for(int i = 2;i < maxn;i++){
19         if(p[i] == 0){
20             for(int j = i;j < maxn;j += i)
21             p[j] = i;
22         }
23     }
24     
25     b[1] = 0;
26     for(int i = 2;i < maxn;i++)
27     b[i] += b[i/p[i]] + 1;
28     
29     for(int i = 1;i < maxn;i++) res[i] += res[i-1] + b[i];
30 }
31 
32 int main(){
33     int n;
34     init();
35     scanf("%d",&n);
36     while(n--){
37         int l,r;
38         scanf("%d %d",&r,&l);
39         printf("%I64d\n",res[r] - res[l]);
40     }
41     return 0;
42 }
View Code

 

cf  416 b

http://codeforces.com/contest/416/problem/B

真是弱爆了---题读了好久才读懂---

递推也没有推出来-----

因为每个画家作当前这幅画的时间有两个开始的时间可以选择,

可以是上一幅画涂完j这种颜色的时间,也可以是这幅画本来就该涂j的时间

想哭开------------------------------------------------------------------------------

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 50005;
 8 int dp[maxn][10];
 9 int a[maxn][10];
10 int m,n;
11 
12 int main(){
13     scanf("%d %d",&m,&n);
14      
15     for(int i = 1;i <= m;i++)
16      for(int j = 1;j <= n;j++) scanf("%d",&a[i][j]);
17      
18      memset(dp,0,sizeof(dp));
19      
20      for(int i = 1;i <= m;i++){
21          for(int j = 1;j <= n;j++){
22              dp[i][j] = max(dp[i-1][j],dp[i][j-1]) + a[i][j];
23          }
24          printf("%d ",dp[i][n]);
25      }
26      printf("\n");
27      return 0;
28 }
View Code

 

---------8.27

 

cf 369 c

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

给一颗n个点,n-1条边的树,有一些边是坏的边,每次可以选择一个点,将这个点到1的边全部变成好边

问把所有的边全部变成好边至少需要选择多少个点------

自己想的是,每一个分支搜下去,搜到底而且这条路径上有坏边的点就被选择----

可是写出来不对---后来翻题解----思路也不对----

翻题解发现写题解的人说-----“最水的树形dp”------呜呜呜呜呜---

应该是这样,搜到当前的一条边是坏边的时候,看它的后代有没有有坏边,

如果没有坏边,这个v点就要被选择

如果有坏边,这个v点就不被选择

 

加油----------------------------------------------------------

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 //wei ziji jiayou >_<
 9 
10 const int maxn = 500005;
11 int d[maxn],first[maxn];
12 int n,ecnt;
13 int flag;
14 vector<int> ans;
15 
16 struct Edge{
17     int v,next,tag;
18 }e[maxn];
19 
20 void init(){
21     ecnt = 0;
22     memset(first,-1,sizeof(first));
23 }
24 
25 void add_edges(int u,int v,int w){
26     e[ecnt].v = v;
27     e[ecnt].next = first[u];
28     e[ecnt].tag = w;
29     first[u] = ecnt++;
30 }
31 
32 bool dfs(int u,int fa){
33     bool flag = false;
34     for(int i = first[u];~i;i = e[i].next){
35         int v = e[i].v;
36         if(v == fa) continue;
37     //    printf("u = %d  v = %d\n",u,v);
38         int ok = dfs(v,u);
39         if(e[i].tag == 2 && !ok){
40                 flag = true;
41                 ans.push_back(v);
42         }
43         if (ok) flag = true;
44     }
45     return flag;
46 }
47 
48 int main(){
49         scanf("%d",&n);
50         init();
51         for(int i = 1;i < n;i++){
52             int u,v,w;
53             scanf("%d %d %d",&u,&v,&w);
54             add_edges(u,v,w);
55             add_edges(v,u,w);
56         }
57         ans.clear();
58         dfs(1,-1);
59         printf("%d\n",ans.size());
60         for(int i = 0;i < ans.size();i++) printf("%d ",ans[i]);
61         printf("\n");
62         return 0;
63 }
View Code

 

cf 489 d

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

给出一个有向图,求图里面的菱形的个数,菱形的定义是,a-->b -->d,a-->c -->d

啊-----傻缺地想到去枚举三个点---------------

枚举菱形的起点和终点,统计可以作为中间的点的个数,每一种起点终点的方案数就是 C(cnt,2)

再累加起来

 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 = 3005;
10 vector<int> g[maxn];
11 int f[maxn][maxn];
12 int n,m;
13 
14 //wei ziji jiayou >_<
15 
16 int main(){
17     while(scanf("%d %d",&n,&m) != EOF){
18         for(int i = 1;i <= n;i++) g[i].clear();
19         memset(f,0,sizeof(f));
20         
21         for(int i = 1;i <= m;i++){
22             int u,v;
23             scanf("%d %d",&u,&v);
24             f[u][v] = 1;
25             g[u].push_back(v);
26         }
27         
28         LL res = 0;
29         LL cnt = 0;
30         
31         for(int a = 1;a <= n;a++){        
32             for(int b = 1;b <= n;b++){
33                 cnt = 0;
34                 if(a == b) continue;
35                 for(int i = 0;i < g[a].size();i++){
36                     int v = g[a][i];
37                     if(v != a && v != b && f[v][b]) cnt++;
38                 }
39                 res += cnt * (cnt-1)/2;
40             }
41         }
42         printf("%I64d\n",res);
43     }
44     return 0;
45 }
View Code

 

cf 320 b

http://codeforces.com/contest/320/problem/B

图建反了,改得好忧桑-----------------

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 int f[105][105];
 9 int n;
10 int vis[105];
11 vector<int> g[105];
12 
13 struct node{
14     int x,y;
15 }a[105];
16 
17 bool dfs(int u,int pos){

18     vis[u] = 1;
19     for(int i = 0;i < g[u].size();i++){
20         int v = g[u][i];
21         if(vis[v]) continue;
22         vis[v] = 1;
23     //    printf("u = %d  v = %d pos = %d\n",u,v,pos);
24         if(v == pos || dfs(v,pos)) return true;
25     }
26     return  false;
27 }
28 
29 int main(){
30     int q;
31     n = 1;
32     memset(f,0,sizeof(f));
33     for(int i = 1;i <= 105;i++) g[i].clear();
34     
35     memset(vis,0,sizeof(vis));
36     scanf("%d",&q);
37     while(q--){
38         int op,x,y;
39         scanf("%d %d %d",&op,&x,&y);
40         
41         if(op == 1) {
42             a[n].x = x; a[n].y = y;
43             for(int i = 1;i < n;i++){
44                 if((a[i].x < a[n].x && a[n].x < a[i].y) || (a[i].x < a[n].y && a[n].y < a[i].y) )
45                 g[n].push_back(i);
46                 
47                 if((a[n].x < a[i].x && a[i].x < a[n].y) || (a[n].x < a[i].y && a[i].y < a[n].y))
48                 g[i].push_back(n);
49             }
50             n++;
51         }
52         else{
53             memset(vis,0,sizeof(vis));
54             if(dfs(x,y)) puts("YES");
55             else puts("NO");
56         }
57     }
58     return 0;
59 }
View Code

 

cf 165 c

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

给出一个0 1 序列,求1的个数为k个的不同的子序列的个数

先算出这个序列的前缀和,计数的时候,算 sum[i] - k在这之前出现的个数

---------------sad---憋两天也没有憋出来-----------------滚了--------

 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 = 1000005;
 9 char s[maxn];
10 LL sum[maxn],cnt[maxn];
11 
12 
13 int main(){
14     int k;
15     scanf("%d",&k);
16     scanf("%s",s+1);
17     int n = strlen(s+1);
18     memset(sum,0,sizeof(sum));
19     for(int i = 1;i <= n;i++){
20         if(s[i] == '0') sum[i] = sum[i-1];
21         else sum[i] = sum[i-1] + 1;
22     }
23     
24     LL res = 0;
25     cnt[0] = 1;
26     for(int i = 1;i <= n;i++){
27         if((sum[i]-k) >= 0 ){
28             res += cnt[sum[i]-k];
29         }
30         cnt[sum[i]]++;
31     }
32     printf("%I64d\n",res);
33 }
View Code

 

---------8.28

cf 349 b

http://codeforces.com/contest/349/problem/B

给定一个钱数m,1到9这9个数字的价钱,问用m去买这些数字,所能够拼凑成的最大的数字

想的是完全背包,再输出路径,只要买尽可能多的数字就可以了

可是挂在了这组数据

898207
99745 99746 99748 99752 99760 99776 99808 99872 100000

完全背包的话,就尽可能地去买第一个数字了,输出的是
111111111
但是可以每种买一个
答案应该是
987654321

所以在想,,,dp应该怎么做呢------

不懂做了---
然后贪心,先排序,求出最长的位数,再用余数和最小的那个数的价钱去替换,看能不能换到更大的数字
 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 int m;
10 
11 struct node{
12     int w,id;
13 }p[maxn];
14 
15 int cmp(node n1,node n2){
16     if(n1.w != n2.w) return n1.w < n2.w;
17     return n1.id > n2.id;
18 }
19 
20 void solve(){
21     sort(p+1,p+10,cmp);
22     int n = m/p[1].w;
23 //    printf("n = %d\n",n);
24     if(n == 0) {
25         puts("-1");
26         return;
27     }
28     
29      int res = m%p[1].w;
30      int maxx,cnt = 0;
31      while(1){
32          int pos = -1,maxx = p[1].id;
33          for(int i = 2;i <= 9;i++){
34              if(res + p[1].w >= p[i].w && maxx < p[i].id){
35                  maxx = p[i].id;
36                  pos = i;
37              }
38          }
39          if(pos == -1) break;
40          res = res + p[1].w - p[pos].w;
41          printf("%d",maxx);cnt++;
42      }
43     // printf("cnt = %d\n",cnt);
44      for(int i = 1;i <= n-cnt;i++) printf("%d",p[1].id);
45      printf("\n");
46 }
47 
48 int main(){
49     while(scanf("%d",&m) != EOF){
50         for(int i = 1;i <= 9;i++) scanf("%d",&p[i].w),p[i].id = i;
51         solve();
52     }
53     return 0;
54 }
View Code

 

cf 253 b

一列数,要使最大的数不超过最小的数的两倍,最少删除多少个数字

枚举起点,upper_bound找终点

还可以用单调队列来做-----看别人的代码很短----等学了再来补上----

话说贴有dp标签的啊------还是不懂该怎么用dp去做

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 100005;
 9 int a[maxn];
10 int n;
11 
12 void solve(){
13     if( a[n-1] <= 2*a[0]) {
14         puts("0");
15         return;
16     }
17     
18     int ans = (1<<30)-1;
19     for(int i = 0;i < n;i++){
20         if(a[i] == a[i-1]) continue;
21         int ub = upper_bound(a,a+n,2*a[i]) - a;
22         int cnt = n-ub;
23         
24     //    printf("i = %d  ub = %d  cnt = %d\n",i,ub,cnt);
25         ans = min(ans,i + cnt);
26     }
27     printf("%d\n",ans);
28 }
29 
30 int main(){
31     freopen("input.txt","r",stdin);
32     freopen("output.txt","w",stdout);
33     while(scanf("%d",&n) != EOF){
34         for(int i = 0;i < n;i++) scanf("%d",&a[i]);
35         
36         sort(a,a+n);
37         solve();
38     }
39     return 0;
40 }
View Code

 

bzoj 1415

做的第一题概率dp,看论文加看题解做的

先假设聪聪在i,可可在j,

再预处理出从i到j的最短路上标号最小的点的编号,用bfs就可以了,因为没有边权

然后dp[i][j]表示从i到j的平均步数

因为可可有两种选择,停留在j,或者去到j的下一个点

所以从i点出发的下一点为 nextu = p[p[i][j]][j],

所以dp[i][j] += dp[nextu][j临接的点](可可去到j的下一点),dp[i][j] += dp[nextu][j](可可停在原地)

dp[i][j] = dp[i][j]/(d[j]+1) + 1(加1是因为聪聪从 i 走到nextu需要一步,d[j]为j点的度数

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<vector>
  6 #include<queue>
  7 #define MP(a,b) make_pair(a,b)
  8 using namespace std;
  9 
 10 typedef pair<int,int> pii;
 11 const int maxn = 1005;
 12 const int INF = (1<<30);
 13 int p[maxn][maxn];
 14 double dp[maxn][maxn];
 15 int vis[maxn],d[maxn];
 16 int n,m,ecnt;
 17 int first[maxn];
 18 int st,ed;
 19 int dis[maxn];
 20 
 21 struct Edge{
 22     int u,v,next;
 23 }e[40*maxn];
 24 
 25 void init(){
 26     ecnt = 0;
 27     memset(d,0,sizeof(d));
 28     memset(first,-1,sizeof(first));
 29     for(int i = 1;i <= n;i++)
 30      for(int j = 1;j <= n;j++) p[i][j] = INF;
 31 }
 32 
 33 void add_edges(int u,int v){
 34     e[ecnt].u = u;
 35     e[ecnt].v = v;
 36     e[ecnt].next = first[u];
 37     first[u] = ecnt++;
 38 }
 39 
 40 void Bfs(int s){
 41     memset(vis,0,sizeof(vis));
 42     for(int i = 1;i <= n;i++) dis[i] = INF;
 43     queue<pii> q;
 44     q.push(MP(s,0)); vis[s] = 1; dis[s] = 0;
 45     
 46     while(!q.empty()){
 47         pii x = q.front();q.pop();
 48         
 49         for(int i = first[x.first];~i;i = e[i].next){
 50             int v = e[i].v;
 51             if(vis[v]){
 52                 if(dis[v] == dis[x.first] + 1 && x.second < p[s][v]){
 53                     p[s][v] = x.second;
 54                     q.push(MP(v,p[s][v]));
 55                 }
 56                 continue;
 57             }
 58             vis[v] = 1;
 59             dis[v] = dis[x.first] + 1;
 60             pii tmp = MP(v,v);
 61             if(x.second != 0) tmp.second = x.second;
 62             p[s][v] = tmp.second;
 63             q.push(tmp);
 64         }
 65     }
 66 }
 67 
 68 void dfs(int u,int w){
 69     if(dp[u][w] >= 0) return;    
 70     if(p[u][w] == w || p[p[u][w]][w] == w){
 71         dp[u][w] = 1.0;
 72         return;
 73     }
 74     dp[u][w] = 0.0;
 75     if(u == w) return;
 76     
 77     int nextu = p[p[u][w]][w],d = 0;
 78     for(int i = first[w];~i;i = e[i].next){
 79         int v = e[i].v;
 80         d++;
 81         dfs(nextu,v);
 82         dp[u][w] += dp[nextu][v];
 83     }
 84     dfs(nextu,w);
 85     dp[u][w] += dp[nextu][w];
 86     dp[u][w] = dp[u][w] /(d +1.0) + 1.0;
 87 }
 88 
 89 void solve(){
 90     for(int i = 1;i <= n;i++) Bfs(i);
 91     
 92     for(int i = 1;i <= n;i++)
 93      for(int j = 1;j <= n;j++) dp[i][j] = -1.0;
 94      
 95      dfs(st,ed);
 96      printf("%.3lf\n",dp[st][ed]);
 97 }
 98 
 99 int main(){
100 //    freopen("in.txt","r",stdin);
101 //    freopen("out.txt","w",stdout);
102     while(scanf("%d %d",&n,&m) != EOF){
103         scanf("%d %d",&st,&ed);
104         init();
105         for(int i = 1;i <= m;i++){
106             int u,v;
107             scanf("%d %d",&u,&v);
108             add_edges(u,v);
109             add_edges(v,u);
110         }
111         solve();
112     }
113     return 0;
114 }
View Code

 

---------8.29

cf 332 b

http://codeforces.com/contest/332/problem/B

给出一列数,求出这列数里面长度为k的序列使得它们的和最大,求这两个序列的起点

用 dp没有想出来----

用RMQ没有想到先处理出n-k个区间的和,去建立d[i][j]-----还是没有想出来---sad--------------

dp的--

相当于在更新两个最大值,,一个是第二个区间的,一个是两个区间合起来的

 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 typedef long long LL;
10 LL dp[maxn],a[maxn];
11 int n,k;
12 
13 //wei ziji jiayou >_<  gooooooooooooooo
14 
15 int main(){
16     scanf("%d %d",&n,&k);
17     memset(dp,0,sizeof(dp));
18     for(int i = 1;i <= n;i++) scanf("%I64d",&a[i]);
19 
20     for(int i = 1;i <= k;i++) dp[1] += a[i];
21     
22     for(int i = 2;i <= n-k+1;i++) dp[i] = dp[i-1] + a[i+k-1] - a[i-1];
23     
24 //    for(int i = 1;i <= n-k+1;i++)
25 //    printf("dp[%d] = %I64d\n",i,dp[i]);
26     
27     int lb = 0,ub = 0,pos = 1;
28     LL Max = 0,max1 = dp[1];
29     
30     for(int i = 1+k;i <= n-k+1;i++){
31         if(dp[i] + max1 > Max){
32             Max = dp[i] + max1;
33             lb = pos;ub = i;
34         }
35         if(dp[i-k+1] > max1){
36             max1 = dp[i-k+1];
37             pos = i-k+1;
38         }
39     //    printf("i = %d  lb = %d  ub = %d  dp[%d] = %I64d  max1 = %I64d Max = %I64d \n",i,lb,ub,i,dp[i],max1,Max);
40     }
41     printf("%d %d\n",lb,ub);
42     return 0;
43 }
View Code


RMQ的--

也相当于在更新最大值,只不过第二个区间找最大值的时候1,用的RMQ

写RMQ改了好久----还是做得太少了-----

加油----------------------------------------

 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 = 200005;
10 LL a[maxn],dp[maxn],d[maxn][32];
11 int n,k;
12 int p; 
13 
14 // wei ziji jiayou  >_< fighttttttt
15 
16 void RMQ_init(){
17     for(int i = 0;i < p;i++) d[i][0] = dp[i];
18     
19     for(int j = 1;(1<<j) <= p;j++)
20      for(int i = 0;i+(1<<j)-1 < p;i++){
21          d[i][j] = max(d[i][j-1],d[i+(1<<(j-1))][j-1]);
22     //    printf("---d[%d][%d] = %I64d\n",i,j,d[i][j]);
23     }
24 }
25 
26 LL RMQ(int L,int R){
27     int k = 0;
28     while((1<<(k+1)) <= R-L+1) k++;
29     return max(d[L][k],d[R-(1<<k)+1][k]);
30 }
31 
32 int main(){
33     scanf("%d %d",&n,&k);
34     for(int i = 0;i < n;i++) scanf("%I64d",&a[i]);
35     
36     memset(dp,0,sizeof(dp));
37     for(int i = 0;i < k;i++) dp[0] += a[i];
38     
39     for(int i = 1;i <= n-k;i++) dp[i] = dp[i-1] + a[i+k-1] - a[i-1];
40     
41 //    for(int i = 0;i <= n-k;i++)
42 //    printf("dp[%d] = %I64d\n",i,dp[i]);
43     
44      p = n-k+1;
45      RMQ_init();
46      
47      
48      //for(int i = 0;i <= n;i++)
49       //for(int j = 0;j <= n;j++)
50       //printf("d[%d][%d] = %I64d\n",i,j,d[i][j]);
51     
52     int lb = 0,ub = 0;
53     LL Max = dp[0],max1 = 0;
54     
55     for(int i = 0;i < p;i++){
56         if(i+k > p-1) continue;
57         LL c1 = RMQ(i+k,p-1);
58     //    printf("dp[%d] = %I64d ",i,dp[i]);
59         LL c2 = dp[i] + c1;
60         if(c2 > Max){
61             Max = c2; max1 = c1;
62             lb = i;
63     //        printf("---lb = %d\n",lb);
64         }
65     //    printf(" i = %d  RMQc1 = %I64d  c2 = %I64d\n",i,c1,c2);
66     }
67     
68     for(int j = lb+k;j <= n-k;j++){
69         if(dp[j] == max1){
70             ub = j;
71             break;
72         }
73     }
74     printf("%d %d\n",lb+1,ub+1);
75     return 0;
76 }
View Code

 

cf 427 c

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

tarjan 求强连通

因为方案数没有取模---wa了几发----

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<stack>
  6 #include<queue>
  7 #include<vector>
  8 using namespace std;
  9 
 10 typedef long long LL;
 11 const int mod = 1e9 + 7;
 12 const int INF = (1<<30)-1;
 13 const int maxn = 200005;
 14 int first[maxn];
 15 int low[maxn],pre[maxn],sc[maxn];
 16 int in[maxn],dout[maxn];
 17 int n,m;
 18 int ecnt,scnt,dfs_clock;
 19 stack<int> S;
 20 
 21 vector<int> g[maxn];
 22 LL a[maxn];
 23 
 24 struct Edge{
 25     int v,next;
 26 }e[3*maxn];
 27 
 28 void init(){
 29     ecnt = 0;
 30     memset(first,-1,sizeof(first));
 31     memset(in,0,sizeof(in));
 32     memset(dout,0,sizeof(dout));
 33 }
 34 
 35 void addedges(int u,int v){
 36     e[ecnt].v = v;
 37     e[ecnt].next = first[u];
 38     first[u] = ecnt++;
 39 }
 40 
 41 void dfs(int u){
 42     low[u] = pre[u] = ++dfs_clock;
 43     S.push(u);
 44     for(int i = first[u];~i;i = e[i].next){
 45         int v = e[i].v;
 46         if(!pre[v]){
 47             dfs(v);
 48             low[u] = min(low[u],low[v]);
 49         }
 50         else if(!sc[v]) low[u] = min(low[u],pre[v]);
 51     }
 52     if(pre[u] == low[u]){
 53         scnt++;
 54         for(;;){
 55             int x = S.top();S.pop();
 56             sc[x] = scnt;
 57             if(x == u) break;
 58         }
 59     }
 60 }
 61 
 62 void find_scc(){
 63     while(!S.empty()) S.pop();
 64     memset(low,0,sizeof(low));memset(pre,0,sizeof(pre));
 65     memset(sc,0,sizeof(sc));
 66     dfs_clock = scnt = 0;
 67     for(int i = 1;i <= n;i++) if(!pre[i]) dfs(i);
 68 }
 69 
 70 
 71 
 72 int main(){
 73         scanf("%d",&n);
 74         init();
 75         memset(a,0,sizeof(a));
 76         for(int i = 1;i <= n;i++) scanf("%I64d",&a[i]);
 77         scanf("%d",&m); 
 78         for(int i = 1;i <= m;i++){
 79             int u,v;
 80             scanf("%d %d",&u,&v);
 81             addedges(u,v);
 82         }
 83         find_scc();
 84         
 85         for(int i = 1;i <= scnt;i++) g[i].clear();
 86         
 87         for(int u = 1;u <= n;u++) g[sc[u]].push_back(u);
 88         
 89         LL res = 0,c = 1;
 90         for(int i = 1;i <= scnt;i++){
 91             LL  c1 = 0,minn = 1LL *INF;
 92             for(int j = 0;j < g[i].size();j++){
 93                 int v = g[i][j];
 94             //    printf("i = %d  v = %d  minn = %I64d\n",i,v,minn);
 95                 if(a[v] < minn) minn = a[v];
 96             }
 97             for(int j = 0;j < g[i].size();j++){
 98                 int v = g[i][j];
 99                 if(a[v] == minn) c1++;
100             }
101             c = (c*c1) % mod;
102             res = res + minn;
103         }
104         printf("%I64d %I64d\n",res,c);
105     return 0;
106 }
View Code

 

然后---下午开始做一道概率dp----

公式好不容易懂的七七八八---

然后--题解说---啊--我们要用矩阵快速幂来优化一下求递推的过程---

好----那我去学一下矩阵快速幂----

于是-----到晚上都没有看懂啊啊啊啊啊------

为什么求的是一个数-----算出来是矩阵该怎么弄-----

 

---------8.30

暑假的最后一天了呢------

话说长这么多年,第一次8月31号要上课-----真是----

 

补昨晚的cf

cf 574 a

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

每次可以减少别的数,增加到第一个数上面来,问需要多少次使得第一个数,比其他所有的数都大

我是个傻缺-----去算了一下最大的数的个数,然后他们轮流给第一个数----直到第一个数比它们大的时候跳出----

可是----最大的数在这个过程中是会变的啊啊啊啊啊----

用优先队列就可以了

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 
 8 int n;
 9 int a[1005];
10 
11 int main(){
12     while(scanf("%d",&n) != EOF){
13         priority_queue<int> q;
14         for(int i = 1;i <= n;i++) {
15             scanf("%d",&a[i]);;
16             if(i != 1) q.push(a[i]);
17         }
18         
19         int ans = 0;
20         while(1){
21             int  x = q.top();q.pop();
22         //    printf("x = %d  a[1] = %d\n",x,a[1]);
23             if(a[1] > x ) break;
24             x--;
25         //    printf("---x = %d \n",x);
26             a[1]++;
27             q.push(x);
28             ans++;
29         }
30         printf("%d\n",ans);
31     }
32     return 0;
33 }
View Code


cf 574 b

http://codeforces.com/contest/574/problem/B

定义一个三元环的值为,这三个点另外连接的不包含环内的点的个数,求值最小的三元环

枚举第一个点,再枚举它临接的点,再看它临接的点临接的点是否有它---维护一个最小值

可是---觉得这样会T掉的----4000*4000*4000

这种临接到的----复杂度应该怎么算啊-------

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 4005;
 9 int a[maxn][maxn];
10 vector<int> g[maxn];
11 int d[maxn];
12 int n,m;
13 
14 int main(){
15     while(scanf("%d %d",&n,&m) != EOF){
16         for(int i = 1;i <= n;i++) g[i].clear();
17         memset(a,0,sizeof(a));
18         memset(d,0,sizeof(d));
19         
20         for(int i = 1;i <= m;i++){
21             int u,v;
22             scanf("%d %d",&u,&v);
23             g[u].push_back(v);
24             g[v].push_back(u);
25             d[u]++;
26             d[v]++;
27             a[u][v] = a[v][u] = 1; 
28         }
29         
30         int ans = (1<<30)-1;
31         int ok = 0;
32         for(int u = 1;u <=  n;u++){
33             for(int i = 0;i < g[u].size();i++){
34                 int v = g[u][i];
35                 for(int j = 0;j < g[v].size();j++ ){
36                     int vv = g[v][j];
37                     if(a[u][vv] || a[vv][u]) {
38                         ok = 1;
39                     //    printf("u = %d v = %d  vv = %d  ",u,v,vv);
40                         ans = min(ans,d[u]-2+d[v]-2+d[vv]-2);
41                     //    printf("ans = %d\n",ans);
42                     }
43                 }
44             }
45         }
46         if(!ok) puts("-1");
47         else printf("%d\n",ans);
48     }
49     return 0;
50 }
View Code

 

poj 3070

矩阵快速幂求斐波那契数列------

终于问----懂---了-------感动哭加蠢哭---

虽然最后求出来的是一个矩阵----

可是输出的是这个矩阵第一行第二列的数,,刚好是和Fn是对应的---

抄了一个模板-

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int mod = 10000;
 9 
10 struct matrix{
11     int mat[3][3];
12     matrix(){
13         memset(mat,0,sizeof(mat));
14     }
15 };
16 
17 matrix mul (matrix A,matrix B){
18     matrix C;
19     for(int i = 1;i <= 2;i++)
20      for(int j = 1;j <= 2;j++)
21       for(int k = 1;k <= 2;k++)
22       C.mat[i][j] = (C.mat[i][j] + A.mat[i][k]*B.mat[k][j]) % mod;
23       return C;
24 }
25 
26 matrix powmul (matrix A,int k){
27     matrix B;
28     B.mat[1][1] = B.mat[2][2] = 1;
29     while(k >= 1){
30         if(k&1) B = mul(B,A);
31         A = mul(A,A);
32         k = k/2;
33     }
34     return B;
35 }
36 
37 int main(){
38     int n;
39     matrix A;
40     while(scanf("%d",&n) && (n+1)){
41         A.mat[1][1] = A.mat[1][2] = A.mat[2][1] = 1;
42         A.mat[2][2] = 0;
43         A = powmul(A,n);
44         printf("%d\n",A.mat[1][2]);
45     }
46     return 0;
47 }
View Code

然后是看的这篇学的,http://blog.csdn.net/y990041769/article/details/39694583#comments

 

cf 574 c

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

给出一列数,可以给每个数不停地乘以2或者3,问最后他们能不能相等---

啊------我是个数学渣渣---

想了半天,想到除以他们的最大公约数,,,然后就没有然后了-------

后来看了题解----

可以画几个数字出来看一下

25*2*3   25*2*2*3*3   25*3  25*5

发现把最大公约数除了之后,变成

2*3       2*2*3*3        3        5

如果是只含有2或者3的话,就可以和别的数差多少个乘多少个,,如果有别的,比如说5,就怎么乘都得不到

所以就判断一下,如果有除了2,3之外的别的因子,就不行

应该再多想一会儿的----呜呜呜---

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 const int maxn = 100005;
 9 int n,g;
10 int a[maxn];
11 
12 int gcd(int a, int b){
13     return (!b) ? a : gcd(b, a % b);
14 }
15 
16 int ok(int x){
17     x = x/g;
18     while(x){
19         if(x % 3 == 0) x = x/3;
20         if(x % 2 == 0) x = x/2;
21         if(x == 1) return 1;
22         if(x%2 != 0 && x%3 != 0) return 0;
23     }
24     return 1;
25 }
26 
27 void solve(){
28      g = gcd(a[1],a[2]);
29         
30     for(int i = 3;i <= n;i++){
31         g = gcd(a[i],g);
32     //    printf("i = %d  g = %d\n",i,g);
33     }
34     
35     for(int i = 1;i <= n;i++){
36         if(!ok(a[i])) {
37             puts("No");
38             return;
39         }
40     }
41     puts("Yes");
42 }
43 
44 int main(){
45     while(scanf("%d",&n) != EOF){
46         for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
47         solve();
48     }
49     return 0;
50 }
View Code

 

hihocoder---1223

http://hihocoder.com/problemset/problem/1223

呜呜呜呜---去做了一下hihocoder---(话说还是第一次做---被打惨---)

给出一堆不等式,问最多能够成立多少个

不等式形如 x < c

我一直wa的做法是这样的-----因为至少有一个不等式是成立的,所以就去枚举每一个不等式,算出其他还能够有几个不等式成立,

再保持一个最大值

 

可是因为题目没有说明 x 是整数,所以这组样例,我的办法就过不了了

6

x = 1

x > 1

x = 3

x < 2

x < 2

x < 2

x < 2

答案应该是5,因为取x = 1.5的时候,就满足了

所以应该去枚举x的值,学习了别人的代码,将每个数的值都乘以2,就相当于把0.5扩大成1了---

话说不懂用string,,,,,输入搞得好繁----

看了人家的string----再看看自己的char s[15]----想一块豆腐拍飞自己------

加油~~~滚了~~

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<vector>
 6 using namespace std;
 7 
 8 
 9 int n;
10 string op[55];
11 int a[55];
12 
13 int ok(int x,int j){
14     if(op[j] == "=") return x == a[j];
15     if(op[j] == "<") return x < a[j];
16     if(op[j] == ">") return x > a[j];
17     if(op[j] == ">=") return x >= a[j];
18     if(op[j] == "<=") return x <= a[j];
19 }
20 
21 void solve(){
22     int ans = 0;
23     for(int i = -1;i < 2010;i ++){
24         int x = 0;
25         for(int j = 1;j <= n;j++){
26             if(ok(i,j)) x++;
27         }
28         ans = max(ans,x);
29     //    printf("i = %lf x = %d\n ",i,x);
30     }
31     printf("%d\n",ans);
32 }
33 
34 int main(){
35     while(scanf("%d",&n) != EOF){
36         for(int i = 1;i <= n;i++){
37             string s;
38             cin >> s >> op[i] >> a[i];
39             a[i] = a[i]*2;
40         }
41         solve();
42     }
43     return 0;
44 }
View Code

 

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值