以后每周写一篇了吧~~
暑假集训就这样结束了的说----
话说起来,还是什么都不会啊----
能够想起来的,就是这一个月,
每周二,多校,周三,补题,周四,多校,剩下,补题-----
感觉自己补题很吃力,有时候半天一天搞懂一道题,有时候还不能自己敲出来--
学了点连通分量,只会模板题,学了一点网络流,可是做的题太少,根本不会建图- -
感觉没有长进----
这种时候~~~又翻翻火影,打打鸡血啊什么的~~~又想到自来也~~
又充满能量~~~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 }
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 }
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 }
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 }
---------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 }
后来下午问了下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 }
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 }
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 }
---------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 }
补上搜索的----
自己写的搜索还是不对,,条理还是不够清晰吧----
木事---加油---
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 }
----------------停电---断网---中-------------
花店橱窗布置
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 }
---------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 }
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 }
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 }
搜题解看到有线段树区间更新写的,,不懂-------
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 }
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 }
---------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 }
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 }
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 }
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 }
---------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 }
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 }
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 }
---------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 }
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 }
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 }
然后---下午开始做一道概率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 }
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 }
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 }
然后是看的这篇学的,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 }
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 }