---------8.31
cf 574 d
http://codeforces.com/contest/574/problem/D
昨天下午就在补,
想出了这个 每一块的消除一次之后的高度为h[i] = min(h[i-1],h[i]-1,h[i+1])
然后,然后,就去模拟了-------TTTTTTT掉----
想半天也不懂怎么优化--
今天看题解了----
消除一次之后为:h[i] = min(h[i-1],h[i]-1,h[i+1])
消除2次之后为:h[i] = max(0,min(h[i-2], h[i-1]-1, h[i]-2 ,h[i+1]-1, h[i+2]))
对于从左边消除的
h[i] = min(h[i-j] - (k-j)) (k为消除次数,j 的范围是0 到k)
当k = h[i-j] + j 的时候,h[i] = 0;
化简一下可以得到,k = ( h[i-j] - (i-j) )+ i;
所以 把 h[i-j] - (i-j)看做一个整体 ,算出最小的h[i]-i,和下标相加就可以了
右边同理
k = ( h[i+j] + (i+j) - i)
还有一种直接递推的
l[i] = min( l[i-1] + 1,h[i])
r[i] = min(r[i+1]+1,h[i])
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 const int maxn = 100005; 8 int h[maxn]; 9 int l[maxn],r[maxn]; 10 int n; 11 12 int main(){ 13 while(scanf("%d",&n) != EOF){ 14 memset(h,0,sizeof(h)); 15 memset(l,0,sizeof(l)); 16 memset(r,0,sizeof(r)); 17 18 for(int i = 1;i <= n;i++) scanf("%d",&h[i]); 19 20 int cnt = 0; 21 for(int i = 1;i <= n;i++){ 22 cnt = min(cnt,h[i]-i); 23 l[i] = cnt+i; 24 } 25 26 cnt = n+1; 27 for(int i = n;i >= 1;i--){ 28 cnt = min(cnt,h[i]+i); 29 r[i] = cnt-i; 30 } 31 32 int ans = 0; 33 for(int i = 1;i <= n;i++) ans = max(ans,min(l[i],r[i])); 34 35 printf("%d\n",ans); 36 } 37 return 0; 38 }
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 const int maxn = 100005; 8 int h[maxn]; 9 int l[maxn],r[maxn]; 10 int n; 11 12 int main(){ 13 while(scanf("%d",&n) != EOF){ 14 memset(h,0,sizeof(h)); 15 memset(l,0,sizeof(l)); 16 memset(r,0,sizeof(r)); 17 18 for(int i = 1;i <= n;i++) scanf("%d",&h[i]); 19 20 for(int i = 1;i <= n;i++) l[i] = min(l[i-1]+1,h[i]); 21 22 for(int i = n;i >= 1;i--) r[i] = min(r[i+1]+1,h[i]); 23 24 int ans = 0; 25 for(int i = 1;i <= n;i++) ans = max(ans,min(l[i],r[i])); 26 27 printf("%d\n",ans); 28 } 29 return 0; 30 }
poj 3071
2 ^ n个队伍比赛,,,相邻的队伍比赛(特别注意这里,,因为刚开始没有看到这儿,后来推编号就一直想不通--)
问哪个队获胜的机率最大
dp[i][j]表示第i场比赛第j支队伍获胜的几率
dp[i][j] = dp[i-1][j] * dp[i-1][k] * p[j][k]
因为既然j在第j场赢了,所以前面i-1场也是赢了的,然后在第 i 场,它需要一个对手k,对手k能够在第i场和它比赛
说明k前i-1场也是赢了的,然后在第 i 场 需要 输给 j,所以再乘上一个 p[j][k]
然后编号k的计算是看这篇看懂的--
http://blog.csdn.net/sr_19930829/article/details/38223757
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 double dp[1025][1025]; 8 double p[1025][1025]; 9 int n; 10 11 int main(){ 12 while(scanf("%d",&n) != EOF && n != -1){ 13 memset(dp,0,sizeof(dp)); 14 memset(p,0,sizeof(p)); 15 16 for(int i = 0;i < (1<<n);i++){ 17 for(int j = 0;j < (1<<n);j++) scanf("%lf",&p[i][j]); 18 } 19 20 for(int j = 0;j < (1<<n);j++) dp[0][j] = 1.0; 21 22 for(int i = 1;i <= n;i++){ 23 for(int j = 0;j < (1<<n);j++){ 24 for(int k = 0;k < (1<<n);k++){ 25 if( (j>>(i-1) ^ 1) == (k >>(i-1)) ){ 26 dp[i][j] += dp[i-1][j] * dp[i-1][k] *p[j][k]; 27 // printf("dp[%d][%d] = %lf\n",i,j,dp[i][j]); 28 } 29 } 30 } 31 } 32 33 double maxx = -1.0; 34 int res = 0; 35 for(int j = 0;j < (1<<n);j++){ 36 if(dp[n][j] > maxx){ 37 maxx = dp[n][j]; 38 res = j+1; 39 } 40 } 41 printf("%d\n",res); 42 } 43 return 0; 44 }
--------- 9.1
新的一个月~加油 O(∩_∩)O ~~~~~~
cf 246 d
http://codeforces.com/contest/246/problem/D
统计每一种颜色临接到的不同颜色最多有多少种
统计一下就好了,最开始没有判断这个颜色是不是存在,被这组数据坑了,
3 2
13 13 4
1 2
最后扫答案的时候判断一下
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #include<set> 7 using namespace std; 8 9 const int maxn = 100005; 10 vector<int> g[maxn]; 11 int n,m; 12 int c[maxn]; 13 vector<int> ans[maxn]; 14 int N; 15 int cnt[maxn]; 16 int vis[maxn]; 17 18 // wei ziji jiayou >_< 19 20 void solve(){ 21 memset(cnt,0,sizeof(cnt)); 22 for(int i = 1;i <= N;i++) ans[i].clear(); 23 for(int u = 1;u <= n;u++){ 24 for(int i = 0;i < g[u].size();i++){ 25 int v = g[u][i]; 26 if(c[u] == c[v]) continue; 27 ans[c[u]].push_back(c[v]); 28 } 29 } 30 31 set<int> s; 32 int res = 0; 33 for(int i = 1;i <= N;i++){ 34 s.clear(); 35 for(int j = 0;j < ans[i].size();j++){ 36 s.insert(ans[i][j]); 37 } 38 int sz = s.size(); 39 // printf("s.size() = %d\n",s.size()); 40 res = max(res,sz); 41 cnt[i] = s.size(); 42 } 43 44 // for(int i = 1;i <= n;i++) 45 // printf("cnt[%d] = %d\n",c[i],cnt[c[i]]); 46 47 for(int i = 1;i <= N;i++){ 48 if(cnt[i] == res && vis[i]){ 49 printf("%d\n",i); 50 return; 51 } 52 } 53 } 54 55 int main(){ 56 while(scanf("%d %d",&n,&m) != EOF){ 57 N = 0; 58 memset(vis,0,sizeof(vis)); 59 for(int i = 1;i <= n;i++) g[i].clear(); 60 for(int i = 1;i <= n;i++) scanf("%d",&c[i]),N = max(c[i],N),vis[c[i]] = 1; 61 for(int i = 1;i <= m;i++){ 62 int u,v; 63 scanf("%d %d",&u,&v); 64 g[u].push_back(v); 65 g[v].push_back(u); 66 } 67 solve(); 68 } 69 return 0; 70 }
cf 161 d
http://codeforces.com/contest/161/problem/D
给出一颗树,问满足点 i 和 点 j 间的距离为 k 的点对有多少对-----
终于弄得略懂了-----感动哭---加 -----蠢哭
dp[i][j] 表示以 i 为 根,距离 i 点 为 j 的点数
当搜索到一个点p的时候,有两种情况
第一种,就是p就是这条链的一个端点,所以直接算就好了
第二种,就是像这个图画的这样
传不了图----
大致 就是跨越过p的情况
所以对于这种情况
肯定是在一个儿子(假设它是儿子1)里面选择了 j ,它的个数为dp[v][j]
在另外一个儿子里面选择了 k-j,它的个数应该怎么算呢(话说这儿真是搞了好久---好捉急)
先统计出p的所有儿子 k-j 的个数,再减去儿子1的k-j的个数,就是可以选择的另外一个的儿子的个数
另外一个儿子的个数 = dp[p][k-1-j] - dp[v][k-2-j]
第一个k-1是因为,儿子1到p有一条边
第二个k-2是因为儿子1到p有一条边,即将要选择的儿子2 到p也有一条边
然后乘起来就可以了----
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 LL dp[maxn][505]; 11 int n,k; 12 LL ans; 13 vector<int> g[maxn]; 14 15 void dfs(int p,int pre){ 16 dp[p][0] = 1; 17 18 for(int i = 0;i < g[p].size();i++){ 19 int v = g[p][i]; 20 if(v == pre) continue; 21 dfs(v,p); 22 for(int j = 1;j <= k;j++) 23 dp[p][j] += dp[v][j-1]; 24 ans += 1LL * dp[v][k-1]; 25 } 26 27 LL tmp = 0; 28 for(int i = 0;i < g[p].size();i++){ 29 int v = g[p][i]; 30 if(v == pre) continue; 31 for(int j = 0;j < k-1;j++){ 32 tmp += 1LL * dp[v][j] * (dp[p][k-j-1] - dp[v][k-j-2]); 33 } 34 } 35 ans += tmp/2; 36 } 37 38 int main(){ 39 while(scanf("%d %d",&n,&k) != EOF){ 40 for(int i = 1;i <= n;i++) g[i].clear(); 41 memset(dp,0,sizeof(dp)); 42 43 44 for(int i = 1;i <= n-1;i++){ 45 int u,v; 46 scanf("%d %d",&u,&v); 47 g[u].push_back(v); 48 g[v].push_back(u); 49 } 50 ans = 0; 51 dfs(1,-1); 52 printf("%I64d\n",ans); 53 } 54 return 0; 55 }
hihocoder 1224
http://hihocoder.com/problemset/problem/1224
给出 n个点,n-1条有向边,每条边的长度都是 1,现在可以在任意的两点之间连一条边,加边之后不能构成环,问能够得到的最长路径
自己不懂做---请教的别人-----也搞了好久--- 捉急---
比如现在也是搜到一个点p,也有两种情况
第一种 :这条路一直往底搜下去就是最长路
第二种:需要拼接一下,将 p 的最长链,次长链拼接在一起,再加上p的深度 就是答案
所以在 dfs 的过程中,mx 在维护当前节点的最长链,更新ans的过程相当于在维护次长链
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 vector<int> g[maxn]; 10 int n,ans; 11 12 int dfs(int u,int d){ 13 ans = max(ans,d); 14 int mx = 0; 15 for(int i = 0;i < g[u].size();i++){ 16 int v = g[u][i]; 17 int f = dfs(v,d+1); 18 if(mx) ans = max(ans,d + mx + f); 19 mx = max(mx,f); 20 } 21 return mx + 1; 22 } 23 24 int main(){ 25 while(scanf("%d",&n) != EOF){ 26 for(int i = 1;i <= n;i++) g[i].clear(); 27 for(int i = 1;i <= n-1;i++){ 28 int u,v; 29 scanf("%d %d",&u,&v); 30 g[u].push_back(v); 31 } 32 dfs(1,0); 33 printf("%d\n",ans); 34 } 35 return 0; 36 }
---------9.2
cf 552 c
http://codeforces.com/problemset/problem/552/C
给出 w ^ 0,w ^ 1,w ^ 2,w ^ 3,------w ^100重的砝码,再给出物品的重量为 m,
每个砝码可以放在左边,不放,或者右边,问能否使得天平平衡
完全没有想到进制那边去-----挫爆了---
将m表示成 w 进制
如果这一位是 0 的话,表示这一个砝码没有放上去,
如果这一位是 1 的话,表示这一个砝码放上去了
如果这一位是w-1的话,说明这个砝码和物品放在了一起(因为放在砝码那一边的话,是 1,所以放到物品这边就应该是 w-1)
然后一位一位地模拟去算就可以了
看的这一篇题解
http://blog.csdn.net/u011265346/article/details/46556361
看人家的代码,,为什么 w == 3,直接输出 yes
后来百度了下,,,三进制也表示所有整数-----
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 int m,w; 11 12 void solve(){ 13 while(m){ 14 int x = m%w; 15 if(x <= 1) m = m/w; 16 else if(x == w-1) m = m/w + 1; 17 else{ 18 printf("NO\n"); 19 return; 20 } 21 } 22 printf("YES\n"); 23 } 24 25 int main(){ 26 while(scanf("%d %d",&w,&m) != EOF){ 27 solve(); 28 } 29 return 0; 30 }
后来又想到爆搜,每个砝码可以放左边,右边,不放,应该搜得出来
然后我就这样去搜的
dfs(l,r,y)
y是当前砝码的质量,l == r 退出
然后依次
dfs(l + y, y,y*w)
dfs(l, r +y,y*w)
dfs(l,r,y*w)
可是这样程序崩掉了-----------------呜呜呜
后来翻了好几页代码---终于找到和我思路一样的
他加了一个剪枝, y < l ,就可以了
可是想不通为什么--------
于是就YY了一个限制搜索深度-----
搜到 d = 10 退出 ,会 wa 85
d = 15退出,会 wa 118
d = 100退出,会 T 2
d = 18 退出,会 T 3
d = 16 退出,好感人,终于过了------
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 INF = (1<<30)-1; 9 LL w,m; 10 11 bool dfs(LL l,LL r,LL y,int d){ 12 //printf("l = %I64d r = %I64d y = %I64d\n ",l,r,y); 13 if(l == r) return true; 14 if(d == 16) return false; 15 if( dfs(l+y,r,y*w,d+1)) return true; 16 if( dfs(l,r,y*w,d+1)) return true; 17 if( dfs(l,r+y,y*w,d+1)) return true; 18 return false; 19 } 20 21 int main(){ 22 // freopen("in.txt","r",stdin); 23 // freopen("out.txt","w",stdout); 24 scanf("%I64d %I64d",&w,&m); 25 if(w < 4) puts("YES"); 26 else{ 27 if(dfs(m,0,1,0)) puts("YES"); 28 else puts("NO"); 29 } 30 return 0; 31 }
cf 519 d
http://codeforces.com/contest/519/problem/D
用map<LL,LL> cnt[26] ,cnt[i][sum]记录当前在第 i 个 字母,前缀和为 sum的个数,
这样扫答案的时候,累加 cnt[i][sum[i]-1]就可以了,(表示这一段的和为0)
-------大致想到了一点这样的思路,,可是想得还是不够清楚,也没有想好用什么去存-----
没事----加油---
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<map> 6 using namespace std; 7 8 typedef long long LL; 9 const int maxn = 100005; 10 map<LL,LL> cnt[26]; 11 int w[30]; 12 LL sum[maxn]; 13 char s[maxn]; 14 15 int main(){ 16 memset(w,0,sizeof(w)); 17 for(int i = 0;i < 26;i++) scanf("%d",&w[i]); 18 scanf("%s",(s+1)); 19 int len = strlen(s+1); 20 21 LL res = 0; 22 memset(sum,0,sizeof(sum)); 23 for(int i = 1;i <= len;i++){ 24 int x = s[i]-'a'; 25 sum[i] += sum[i-1] + w[x]; 26 res += cnt[x][sum[i-1]]; 27 cnt[x][sum[i]]++; 28 // printf("cnt[%d][%I64d] = %d\n",x,sum[i],cnt[x][sum[i]]); 29 } 30 printf("%I64d\n",res); 31 return 0; 32 }
于是---后来,看到这场 cf 是 294 div 2,,,心想这个以前做过的啊,,现在把题目给补完吧-----
too young------
蠢蠢的写了3个dfs的E,,妥妥的T掉了---
于是搜了题解----
又是 在线的LCA---------------
滚去学了---------------------------------------------
---------9.3
cf 329 b
http://codeforces.com/contest/329/problem/B
没有读懂题啊,,,,
先是这样想的,把每一伙人按人数从少到多排序,看哪一伙能到达起点,就是必须消灭掉的最少人数
可是,,,事实上题意是这样的---
不管怎么样,敌人肯定会千方百计地来攻击你,所以如果它到终点的最短距离比你到终点的最短距离小的话
敌人就可以先到终点去等着你,再和你打一架
所以bfs出终点到每个点的最短距离,累加上距离小于到你的距离的就可以了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 8 const int maxn = 1005; 9 const int INF = (1<<30)-1; 10 char g[maxn][maxn]; 11 int n,m,cnt; 12 int d[maxn][maxn],vis[maxn][maxn]; 13 int ex,ey,sx,sy; 14 15 int dir[4][2] = {1,0,-1,0,0,1,0,-1}; 16 17 struct node{ 18 int x,y; 19 int num; 20 int d; 21 }a[maxn*maxn]; 22 23 void bfs(){ 24 memset(vis,0,sizeof(vis)); 25 queue<node> q; 26 q.push(node{ex,ey,0,0}); 27 vis[ex][ey] = 1; 28 d[ex][ey] = 0; 29 30 while(!q.empty()){ 31 node u = q.front();q.pop(); 32 33 for(int i = 0;i < 4;i++){ 34 int xx = u.x + dir[i][0]; 35 int yy = u.y + dir[i][1]; 36 if(xx <= 0 || xx > n || yy <= 0 || yy > m || vis[xx][yy] || g[xx][yy] == 'T') continue; 37 vis[xx][yy] = 1; 38 d[xx][yy] = u.d + 1; 39 q.push(node{xx,yy,0,d[xx][yy]}); 40 } 41 } 42 } 43 44 int main(){ 45 scanf("%d %d",&n,&m); 46 47 cnt = 1; 48 for(int i = 1;i <= n;i++){ 49 for(int j = 1;j <= m;j++){ 50 cin >> g[i][j]; 51 if(g[i][j] == 'E') ex = i,ey = j; 52 if(g[i][j] == 'S') sx = i,sy = j; 53 if(g[i][j] > '0' && g[i][j] <= '9'){ 54 a[cnt].x = i; 55 a[cnt].y = j; 56 a[cnt].d = 0; 57 a[cnt++].num = g[i][j] -'0'; 58 } 59 } 60 } 61 62 for(int i = 1;i <= n;i++) 63 for(int j = 1;j <= m;j++) d[i][j] = INF; 64 65 bfs(); 66 67 int res = 0; 68 for(int i = 1;i <= cnt;i++){ 69 int x = a[i].x ; 70 int y = a[i].y; 71 if(d[x][y] <= d[sx][sy]) res += a[i].num; 72 } 73 printf("%d\n",res); 74 75 return 0; 76 }
cf 159 d
http://codeforces.com/problemset/problem/159/D
没有自己想出来----好忧郁----
没事---继续加油---
求一个字符串里面回文串的对数
维护一个以i结尾的回文串的个数 r[i],以i开头的回文串的个数 l[i]
算答案的时候,扫到第 i 个位置的时候,就 ans = r[i] * l[i+1]
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 = 2005; 10 char s[maxn]; 11 int l[maxn],r[maxn]; 12 13 int main(){ 14 memset(l,0,sizeof(l)); 15 memset(r,0,sizeof(r)); 16 scanf("%s",s); 17 int len = strlen(s); 18 19 for(int i = 0;i < len;i++){ 20 for(int a = i,b = i+1; a >= 0 && b < len && s[a] == s[b];a--,b++){ 21 l[a]++; 22 r[b]++; 23 } 24 for(int a = i,b = i; a >= 0 && b < len && s[a] == s[b];a--,b++){ 25 l[a]++; 26 r[b]++; 27 } 28 } 29 30 // for(int i = 0;i < len;i++) 31 // printf("l[%d] = %d r[%d] = %d\n",i,l[i],i,r[i]); 32 33 LL ans = 0; 34 for(int i = 0;i < len;i++) r[i] += r[i-1]; 35 for(int i = 0;i < len;i++){ 36 ans += r[i] * l[i+1]; 37 } 38 printf("%I64d\n",ans); 39 return 0; 40 }
cf 359 b
http://codeforces.com/contest/359/problem/B
构造,看k等于几,就换几下位置就好了
先没有看清楚k的范围,用k为公差来构造的,waaaaaa---
仔细一点-----可是贴有dp的标签,,,dp该怎么做---
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 = 50005; 9 int a[2*maxn]; 10 int n,k; 11 12 void solve(){ 13 for(int i = 1;i <= 2*n;i++) a[i] = i; 14 if(k == 0) return; 15 16 int cnt = 0; 17 int pos = 1; 18 while(cnt < k){ 19 cnt++; 20 swap(a[pos],a[pos+1]); 21 pos = pos+2; 22 } 23 } 24 25 int main(){ 26 memset(a,0,sizeof(a)); 27 scanf("%d %d",&n,&k); 28 solve(); 29 for(int i = 1;i <= 2*n;i++) 30 printf("%d ",a[i]); 31 printf("\n"); 32 return 0; 33 }
cf 264 b
http://codeforces.com/problemset/problem/264/B
给定一个上升序列,问满足相邻的两项不互质的最长序列的长度
最开始没有看到是给定的序列就是单增的,就在想是不是最长上升子序列的变形呢---
还是没有想出来
只想出来,dp[i] 以 i 为结尾的最长序列的长度
dp[i] = max(dp[j] + 1), 0 <= j < i,其中 gcd(a[i],a[j]) > 1
可是是 n^2,都没有去打----
看的这篇题解http://blog.csdn.net/zucc_dianbei/article/details/8523301
考虑转移的时候,把a[i]这个数放在哪里,只要含有 a[i] 的质因子的话,就可以满足a[i]加入进去,gcd(x,a[i]) > 1,
所以维护一个max[prime],表示包含prime这个素因子的当前计算到的所有dp值里面的最大值
dp[i] = max(dp[i],max[i的素因子] + 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 = 100005; 9 int dp[maxn],a[maxn]; 10 int Max[maxn]; 11 vector<int> p[maxn]; 12 int n; 13 int vis[maxn]; 14 15 int main(){ 16 memset(vis,0,sizeof(vis)); 17 vis[0] = vis[1] = 1; 18 19 for(int i = 2;i <= maxn;i++){ 20 if(vis[i] == 0){ 21 for(int j = i;j <= maxn;j+=i) p[j].push_back(i),vis[j] = 1; 22 } 23 } 24 25 scanf("%d",&n); 26 for(int i = 1;i <= n;i++) scanf("%d",&a[i]); 27 28 memset(Max,0,sizeof(Max)); 29 30 for(int i = 1;i <= n;i++) dp[i] = 1; 31 for(int i = 1;i <= n;i++){ 32 int t = a[i]; 33 for(int j = 0;j < p[t].size();j++) 34 dp[i] = max(dp[i],Max[p[t][j]]+1); 35 for(int j = 0;j < p[t].size();j++) 36 Max[p[t][j]] = max(dp[i],Max[p[t][j]]); 37 } 38 39 int res = 0; 40 for(int i = 1;i <= n;i++) res = max(res,dp[i]); 41 printf("%d\n",res); 42 return 0; 43 }
---------9.4
天气变凉快了,路边的树上又开满了红色的花,加油! ! !
cf 118 d
http://codeforces.com/problemset/problem/118/D
给出 n1个步兵,n2个骑兵,要求连续的骑兵的个数不超过 k1个,连续的步兵的个数不超过 k2 个 的排列方案的总数。
还是不会dp---
用排列组合去做的,一点都不对---
应该这样
dp[i][j][0] 表示步兵的个数为 i ,骑兵的个数为 j 的时候,步兵的个数不超过 k1 的方案数
dp[i][j][1] 表示步兵的个数为 i ,骑兵的个数为 j 的时候,骑兵的个数不超过 k2 的方案数
然后就可以转移了
自己写的时候,答案推出来老是更小,是因为初始化没有写对
应该 dp[i][0][0] = 1,1<= i <= k1 dp[0][i][1] = 1 , 1 <= i <= k2
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 = 1e8; 9 LL dp[105][105][2]; 10 int n1,n2,k1,k2; 11 12 int main(){ 13 while(scanf("%d %d %d %d",&n1,&n2,&k1,&k2) != EOF){ 14 memset(dp,0,sizeof(dp)); 15 for(int i = 1;i <= k1;i++) dp[i][0][0] = 1; 16 for(int i = 1;i <= k2;i++) dp[0][i][1] = 1; 17 18 for(int i = 1;i <= n1;i++){ 19 for(int j = 1;j <= n2;j++){ 20 for(int k = 1;k <= min(i,k1);k++){ 21 dp[i][j][0] = (dp[i][j][0] + dp[i-k][j][1]) % mod; 22 // printf("dp[%d][%d][0] = %I64d\n",i,j,dp[i][j][0]); 23 } 24 for(int k = 1;k <= min(j,k2);k++){ 25 dp[i][j][1] = (dp[i][j][1] + dp[i][j-k][0])%mod; 26 // printf("dp[%d][%d][1] = %I64d\n",i,j,dp[i][j][1]); 27 } 28 } 29 } 30 printf("%I64d\n",(dp[n1][n2][0] + dp[n1][n2][1])%mod); 31 } 32 return 0; 33 }
下午又变热了 ----
cf 472 d
http://codeforces.com/contest/472/problem/D
给出 n个点之间的最短距离矩阵,问这n个点是否构成一颗树
先想到最短距离,就跑最短路,再和原来的矩阵比较,不一样的话,就不能
于是----建立了 2*n*n-n条边
再以每个点为起点跑dijkstra,再和原矩阵比较,妥妥的T掉了----
应该这样,先对这个距离矩阵求一次最小生成树出来,再以每个点为根,去dfs出到其余n-1个点的最短距离,再进行对照
刚开始想不通为什么一定要建立最小生成树再dfs
后来想,因为是最短距离,最小生成树上的就是最小距离了,如果在最小生成树上找都不能够满足,那就不会满足了
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<vector> 6 #include<queue> 7 #include<map> 8 #include<set> 9 #define MP(a,b) make_pair(a,b) 10 using namespace std; 11 12 typedef long long LL; 13 typedef pair<int,int> pii; 14 const int maxn = 2005; 15 int d[maxn][maxn]; 16 int ecnt,first[maxn]; 17 int a[maxn][maxn]; 18 int n; 19 int p[maxn]; 20 int vis[maxn]; 21 22 struct Edge{ 23 int u,v,next,cost; 24 }e[2*maxn*maxn]; 25 26 Edge e1[maxn*maxn]; 27 28 struct cmp{ 29 bool operator ()(pii a,pii b){ 30 return a.first > b.first; 31 } 32 }; 33 34 void init(){ 35 ecnt = 0; 36 memset(first,-1,sizeof(first)); 37 } 38 39 void add_edges(int u,int v,int w){ 40 e[ecnt].v = v; 41 e[ecnt].cost = w; 42 e[ecnt].next = first[u]; 43 first[u] = ecnt++; 44 } 45 46 int cmp1(Edge e1,Edge e2){return e1.cost < e2.cost;} 47 48 int find(int x){return x == p[x] ? x :p[x] = find(p[x]);} 49 50 void dfs(int u,int s){ 51 vis[u] = 1; 52 for(int i = first[u];~i;i = e[i].next){ 53 int v = e[i].v; 54 if(vis[v]) continue; 55 d[s][v] = d[s][u] + e[i].cost; 56 dfs(v,s); 57 } 58 } 59 60 void solve(){ 61 for(int i = 1;i <= n;i++){ 62 for(int j = 1;j <= n;j++){ 63 if((i == j && a[i][j] != 0) || (i != j && a[i][j] == 0)){ 64 puts("NO"); 65 return; 66 } 67 } 68 } 69 70 int tot = 0; 71 for(int i = 1;i <= n;i++){ 72 for(int j = 1;j <= n;j++){ 73 if(i == j) continue; 74 e1[tot].u = i; e1[tot].v = j;e1[tot++].cost = a[i][j]; 75 } 76 } 77 78 sort(e1,e1+tot,cmp1); 79 for(int i = 1;i <= n;i++) p[i] = i; 80 for(int i = 0;i < tot;i++){ 81 int u = e1[i].u; 82 int v = e1[i].v; 83 int x = find(u); 84 int y = find(v); 85 if(x != y){ 86 p[x] = y; 87 add_edges(u,v,a[u][v]); 88 add_edges(v,u,a[u][v]); 89 } 90 } 91 92 for(int i = 1;i <= n;i++){ 93 d[i][i] = 0; 94 memset(vis,0,sizeof(vis)); 95 dfs(i,i); 96 for(int j = 1;j <= n;j++){ 97 if(d[i][j] != a[i][j]){ 98 puts("NO"); 99 return; 100 } 101 } 102 } 103 puts("YES"); 104 } 105 106 int main(){ 107 while(scanf("%d",&n) != EOF){ 108 init(); 109 for(int i = 1;i <= n;i++) 110 for(int j = 1;j <= n;j++) scanf("%d",&a[i][j]); 111 112 solve(); 113 } 114 return 0; 115 }
补一个搜题解的时候看到的另外的办法
想法还是和最小生成树的想法有一点像
先选择一个点 a,再从 a 临接到的边里面扫一遍,找出距离最短的边,记这条边的另一个端点为 b
可以证明这条边一定在最小生成树上
可以反证一下,假设这条边不在最小生成树上,最小距离的都不在,肯定不满足最小生成树
所以,它一定在
然后再去扫一遍所有的顶点k ,因为 a 到 b 是最短距离,所以 a 和 b之间是直接连接的
那么 满足abs(d[a][k] - d[k][b]) = d[a][b]的话就符合
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 8 const int maxn = 2005; 9 int d[maxn][maxn]; 10 int n; 11 12 void solve(){ 13 for(int i = 1;i <= n;i++){ 14 for(int j = 1;j <= n;j++){ 15 if((i == j && d[i][j] != 0) || (i != j && d[i][j] == 0)){ 16 puts("NO"); 17 return; 18 } 19 } 20 } 21 22 int minn = (1<<30)-1,v; 23 for(int i = 1;i <= n;i++){ 24 minn = (1<<30)-1; 25 for(int j = 1;j <= n;j++){ 26 if(i == j) continue; 27 if(d[i][j] < minn){ 28 minn = d[i][j]; 29 v = j; 30 } 31 } 32 for(int k = 1;k <= n;k++){ 33 if(k == i || k == v) continue; 34 if(abs(d[i][k] - d[k][v]) != minn){ 35 puts("NO"); 36 return; 37 } 38 } 39 } 40 puts("YES"); 41 } 42 43 int main(){ 44 while(scanf("%d",&n) != EOF){ 45 memset(d,0,sizeof(d)); 46 for(int i = 1;i <= n;i++) 47 for(int j = 1;j <= n;j++) scanf("%d",&d[i][j]); 48 49 solve(); 50 } 51 return 0; 52 }
cf 131 d
http://codeforces.com/problemset/problem/131/D
这道题的进步在于,,读完题,,瞅完样例,,我知道题目要让我干嘛了---
就是找到图里面唯一的那个环,然后找出其他点到这个环的距离
可是不会dfs找环
知道应该是如果dfs到一个已经访问过的点,那么就找到了一个环,,可是不会写---
学了这一篇---
http://www.cnblogs.com/wally/p/4477074.html
啊----好好理解-----------------------------------------------
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<queue> 5 using namespace std; 6 7 const int maxn = 3005; 8 int vis[maxn]; 9 int huan[maxn]; 10 int d[maxn]; 11 vector<int> g[maxn]; 12 int n,st; 13 int findd ,ok; 14 15 void dfs(int u,int fa){ 16 vis[u] = 1; 17 for(int i = 0;i < g[u].size();i++){ 18 int v = g[u][i]; 19 if(v == fa) continue; 20 if(!vis[v]) dfs(v,u); 21 else{ 22 findd = 1;st = v;huan[u] = 1;return; 23 } 24 if(findd){ 25 if(ok) return; 26 if(st == u) ok = 1; 27 huan[u] = 1; 28 return; 29 } 30 } 31 } 32 33 void bfs(int s){ 34 memset(d,0,sizeof(d)); 35 memset(vis,0,sizeof(vis)); 36 queue<int> q; 37 q.push(s);vis[s] = 1;d[s] = 0; 38 while(!q.empty()){ 39 int u = q.front();q.pop(); 40 for(int i = 0;i < g[u].size();i++){ 41 int v = g[u][i]; 42 if(vis[v]) continue; 43 vis[v] = 1; 44 q.push(v); 45 if(huan[v]) d[v] = 0; 46 else d[v] = d[u]+1; 47 } 48 } 49 } 50 51 int main(){ 52 while(scanf("%d",&n) != EOF){ 53 for(int i = 1;i <= n;i++) g[i].clear(); 54 for(int i = 1;i <= n;i++){ 55 int u,v; 56 scanf("%d %d",&u,&v); 57 g[u].push_back(v); 58 g[v].push_back(u); 59 } 60 61 memset(vis,0,sizeof(vis)); 62 findd = ok = 0; 63 dfs(1,0); 64 bfs(st); 65 for(int i = 1;i <= n;i++) 66 printf("%d ",d[i]); 67 printf("\n"); 68 } 69 return 0; 70 }
---------9.5
poj 1274
二分图最大匹配裸题,存个模板
之前学过,,可是也只看过算法,没有做过题目-----
这篇这篇超生动 http://blog.csdn.net/dark_scope/article/details/8880547
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,m; 10 int used[maxn],mat[maxn]; 11 vector<int> g[maxn]; 12 13 void init(){ 14 memset(mat,0,sizeof(mat)); 15 for(int i = 1;i <= n;i++) g[i].clear(); 16 } 17 18 bool find(int p){ 19 for(int i = 0;i < g[p].size();i++){ 20 int v = g[p][i]; 21 if(!used[v]){ 22 used[v] = 1; 23 if(!mat[v] || find(mat[v])){ 24 mat[v] = p; 25 return true; 26 } 27 } 28 } 29 return false; 30 } 31 32 int Hungary(){ 33 int res = 0; 34 for(int i = 1;i <= n;i++) { 35 memset(used,0,sizeof(used)); 36 if(find(i)) res++; 37 } 38 return res; 39 } 40 41 int main(){ 42 while(scanf("%d %d",&n,&m) != EOF){ 43 init(); 44 for(int i = 1;i <= n;i++){ 45 int a,u; 46 scanf("%d",&a); 47 for(int j = 1;j <= a;j++){ 48 scanf("%d",&u); 49 g[i].push_back(u); 50 } 51 } 52 printf("%d\n",Hungary()); 53 } 54 return 0; 55 }
hdu 1533
二分图最小权匹配
和二分图最大权匹配一样,只是建图的时候,把边权加个负号,输出答案的时候,把答案加个负号
其实还是不是很理解可行顶标-----
抄个模板---
等搞懂了再来补上--
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #include <string> 5 #include <iostream> 6 #include <algorithm> 7 using namespace std; 8 9 const double eps = 1e-8; 10 const int INF = (1 << 30) - 1; 11 const int M = 210; 12 13 int n,nx,ny,m,r,c; 14 int link[M],lx[M],ly[M],slack[M]; //lx,ly为顶标, slack为可改进量 15 int visx[M],visy[M],w[M][M]; 16 17 int Dfs(int x){ 18 visx[x] = 1; 19 for (int y = 1;y <= ny;y ++){ 20 if (visy[y]) 21 continue; 22 int t = lx[x] + ly[y] - w[x][y]; 23 if (t == 0){ 24 visy[y] = 1; 25 if (link[y] == -1 || Dfs(link[y])){ 26 link[y] = x; 27 return 1; 28 } 29 } 30 else if (slack[y] > t) 31 slack[y] = t; 32 } 33 return 0; 34 } 35 36 int KM(){ 37 int i,j; 38 memset (link,-1,sizeof(link)); 39 memset (ly,0,sizeof(ly)); //ly 初始化为 0 40 for (i = 1;i <= nx;i ++) //lx初始化为与它关联边中最大的 41 for (j = 1,lx[i] = -INF;j <= ny;j ++) 42 if (w[i][j] > lx[i]) 43 lx[i] = w[i][j]; 44 for (int x = 1;x <= nx;x ++){ 45 for (i = 1;i <= ny;i ++) 46 slack[i] = INF; 47 while (1){ 48 memset (visx,0,sizeof(visx)); 49 memset (visy,0,sizeof(visy)); 50 if (Dfs(x)) //如果找到增广路,说明这个点增广完成,跳出,进入下一个点的增广 51 break; //如果失败的话,就要修改顶标, 52 //方法是将在增广过程中遇到的X的顶标全部减去d,将遇到的Y的顶标全部加上d 53 54 int d = INF; 55 for (i = 1;i <= ny;i ++) 56 if (!visy[i]&&d > slack[i]) 57 d = slack[i]; 58 for (i = 1;i <= nx;i ++) 59 if (visx[i]) 60 lx[i] -= d; 61 for (i = 1;i <= ny;i ++) 62 if (visy[i]) 63 ly[i] += d; 64 else 65 slack[i] -= d; 66 } 67 } 68 int res = 0; 69 for (i = 1;i <= ny;i ++) 70 if (link[i] > -1) 71 res += w[link[i]][i]; 72 return res; 73 } 74 75 char g[M][M]; 76 77 struct node{ 78 int x,y; 79 }house[M],men[M]; 80 81 int cal(int x,int y){ 82 return abs(house[x].x - men[y].x) + abs(house[x].y - men[y].y); 83 } 84 85 int main(){ 86 while(scanf("%d %d",&r,&c) != EOF && r && c){ 87 nx = ny = 0; 88 for(int i = 1;i <= r;i++) scanf("%s",g[i]+1); 89 90 for(int i = 1;i <= r;i++){ 91 for(int j = 1;j <= c;j++){ 92 if(g[i][j] == 'H') house[++nx].x = i,house[nx].y = j; 93 if(g[i][j] == 'm') men[++ny].x = i,men[ny].y = j; 94 } 95 } 96 97 for(int i = 1;i <= nx;i++){ 98 for(int j = 1;j <= ny;j++){ 99 w[i][j] = -cal(i,j); 100 } 101 } 102 printf("%d\n",-KM()); 103 } 104 return 0; 105 }
搞懂一点点可行顶标了
因为,可行顶标是一个节点函数 l,使得对于任意弧 (x,y) 有 l(x) + l(y) >= w[x][y]
对于相等子图
l[x] + l[y] = w[x][y]
所以,如果现在 X 端 在 S,Y端不在 T
给 X 端减去一个 d, Y端因为不在 T,不变
此时 的 l[x] + l[y] 整1体就减小了 d ,就有可能等于 w[x][y],进入相等子图
先不做二分图这些吧-----还是滚去做dp,dfs好了-----
cf 500 d
http://codeforces.com/problemset/problem/500/D
-------做到这道题真是好怀念啊啊啊啊啊啊---
记得那天晚上刚好是平安夜
宿舍在一起玩了一晚上
期待着下雪却没有下
吃了好多
还有好多苹果
然后0点半做cf------
现在想起来那段日子真是太棒啦----
加油---------------------------------------
给出一颗树,从中任意选三个点 c1,c2,c3,组成一个三角形,这样的一个三角形的权值为 d[c1][c2] + d[c2][c3] + d[c1][c3]
然后给出 q次询问,每次把第 x 条边的边权 改成 y,求取出来的三角形的权值的期望
先dfs处理出每个节点的子节点个数
然后计算每一条边对答案的贡献,这种想法又有点像上上次BC做到的那个差分前缀和求每个区间的贡献那样
画一下图就可以知道了
然后再乘以概率是 C(n-2,1)/ C(n,3)
即 分子,在一条边(两个点)已经确定的情况下,还需要选一个点,是 C(n-2,1)
分母,从 n 个点里面选3 个点出来 是 C(n,3)
然后这题各种爆int------后来有乘的地方都加上 1LL ------
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 = 100005; 10 int n,q; 11 int sz[maxn]; 12 int vis[maxn]; 13 14 int ecnt,first[maxn],c[maxn]; 15 LL d[maxn]; 16 struct Edge{ 17 int u,v,w; 18 int next; 19 }e[5*maxn]; 20 21 void init(){ 22 ecnt = 0; 23 memset(first,-1,sizeof(first)); 24 } 25 26 void add_edges(int u,int v,int w){ 27 e[ecnt].u = u; 28 e[ecnt].v = v; 29 e[ecnt].next = first[u]; 30 first[u] = ecnt++; 31 } 32 33 void dfs(int u){ 34 vis[u] = 1; 35 sz[u] = 1; 36 for(int i = first[u];~i;i = e[i].next){ 37 int v = e[i].v; 38 if(vis[v]) continue; 39 dfs(v); 40 sz[u] += sz[v]; 41 } 42 } 43 44 int main(){ 45 while(scanf("%d",&n) != EOF){ 46 init(); 47 memset(c,0,sizeof(c)); 48 memset(d,0,sizeof(d)); 49 50 for(int i = 1;i <= n-1;i++){ 51 int u,v,w; 52 scanf("%d %d %d",&u,&v,&w); 53 add_edges(u,v,w); 54 add_edges(v,u,w); 55 c[i] = w; 56 } 57 memset(vis,0,sizeof(vis)); 58 dfs(1); 59 60 for(int i = 1;i < n;i++){ 61 int u = e[2*i-1].u; 62 int v = e[2*i-1].v; 63 int l = min(sz[u],sz[v]); 64 int r = n - l; 65 d[i] = 1LL*l*1LL*r; 66 // printf("i = %d u = %d v = %d d[%d] = %d\n",i,u,v,i,d[i]); 67 } 68 69 LL res = 0; 70 double p = 6.0/(1LL*n*(n-1)); 71 for(int i = 1;i <= n-1;i++){ 72 res += c[i]*d[i]; 73 } 74 75 scanf("%d",&q); 76 while(q--){ 77 int x,y; 78 scanf("%d %d",&x,&y); 79 res -= 1LL*(c[x]-y)*d[x]; 80 printf("%lf\n",(double)res*p); 81 c[x] = y; 82 } 83 } 84 return 0; 85 }
poj 3744 Scout YYF I
题解这里--http://www.cnblogs.com/ka200812/archive/2012/08/29/2661876.html
递推式 很好懂
然后,不懂的是坐标离散化那个过程----
终于略懂一点点,不知道对不对
假设现在有n个雷,那么现在就有 n 段
因为dp[i]表示的是安全到达某一点的概率,所以就可以将dp[i] 都乘起来
可是坐标太大了
然后考虑安全通过每一段的,等于 1减去 踩到第i个雷的概率
然后这个说明从 x[i-1] + 1 到 x[i] -1 这些点是安全通过了的
所以算答案的时候,那个幂次就是 安全通过的点数,x[i] -(x[i-1]+1)
还有----有点坑的是,交 G++,要 printf %.7f
交C++,就可以 printf %.7lf
不懂为什么----
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 struct mat{ 8 double a[2][2]; 9 mat(){ 10 for(int i = 0;i < 2;i++) 11 for(int j = 0;j < 2;j++) a[i][j] = 0; 12 } 13 }; 14 15 mat e; 16 int n,x[105]; 17 double p; 18 19 mat mul (mat a,mat b){ 20 mat ans; 21 for(int i = 0;i < 2;i++) 22 for(int j = 0;j < 2;j++) 23 for(int k = 0;k < 2;k++) 24 ans.a[i][j] += a.a[i][k] * b.a[k][j]; 25 return ans; 26 } 27 28 double matpow(mat a, int k){ 29 mat ans = e; 30 while(k){ 31 if(k&1) ans = mul(ans,a); 32 a= mul(a,a); 33 k = k >> 1; 34 } 35 return ans.a[0][0]; 36 } 37 38 int main(){ 39 e.a[0][0] = 1;e.a[0][1] = 0; 40 e.a[1][0] = 0;e.a[1][1] = 1; 41 while(scanf("%d%lf",&n,&p) == 2){ 42 x[0] = 0; 43 for(int i = 1;i <= n;i++) scanf("%d",&x[i]); 44 sort(x+1,x+n+1); 45 46 mat res; 47 res.a[0][0] = p;res.a[0][1] = 1-p; 48 res.a[1][0] = 1;e.a[1][1] = 0; 49 50 double ans = 1.0; 51 for(int i = 1;i <= n;i++){ 52 ans *= (1.0 - matpow(res,x[i]-(x[i-1]+1))); 53 } 54 printf("%.7lf\n",ans); 55 } 56 return 0; 57 }
---------9.6
昨晚的bc真是挫爆了
第一题被坑好久,第二题后来被卡掉了,第三题不会高精度,第四题不会---
可以滚了
没事,反正也不是第一次这么挫,下次可能还会更挫
加油加油------------------------------------------------------------------------
hdu 5428 The Factor
先用的筛法求的素数,筛到 100000,再找的最小的两个素因子,被卡掉了
改不对
----知道哪里有问题了---
搜了一下大素数,一亿以内的最大素数是99999989 ,这样筛法数组就开不下来,就筛不出来了
然后假如数组开到1e7,再在1e7到2e9 之间随便找两个素数,答案就不对了
看了别人这样筛的-----
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<vector> 7 #include<set> 8 using namespace std; 9 10 typedef long long LL; 11 const int maxn = 100005; 12 int dp[maxn]; 13 int Max[maxn]; 14 vector<int> p; 15 16 int vis[maxn]; 17 int T,n,a[105]; 18 int cnt[maxn]; 19 multiset<int> s; 20 21 void solve( int x){ 22 int y = a[x]; 23 for(int j = 2;j*j <= y;j++){ 24 if(y%j == 0){ 25 while(y%j == 0){ 26 s.insert(j); 27 y = y/j; 28 } 29 } 30 } 31 if(y > 1) s.insert(y); 32 } 33 34 void work(){ 35 if(s.size() < 2){ 36 puts("-1"); 37 return; 38 } 39 multiset<int>::iterator it; 40 41 it = s.begin(); 42 LL c1 = *it; 43 ++it; 44 LL c2 = *it; 45 printf("%I64d\n",c1*c2); 46 } 47 48 int main(){ 49 50 scanf("%d",&T); 51 while(T--){ 52 s.clear(); 53 54 memset(cnt,0,sizeof(cnt)); 55 scanf("%d",&n); 56 for(int i = 1;i <= n;i++) scanf("%d",&a[i]); 57 58 for(int i = 1;i <= n;i++){ 59 solve(i); 60 } 61 work(); 62 } 63 return 0; 64 }
然后自己写的,是因为素数没有筛完,这样改一下,
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 #include<vector> 7 #include<set> 8 using namespace std; 9 10 typedef long long LL; 11 const int maxn = 200005; 12 int dp[maxn]; 13 int Max[maxn]; 14 vector<int> p; 15 16 int vis[maxn]; 17 int T,n,a[105]; 18 int cnt[maxn]; 19 multiset<int> s; 20 21 void is(){ 22 memset(vis,0,sizeof(vis)); 23 int m = sqrt(2e9+0.5); 24 for(int i = 2;i <= m;i++) if(!vis[i]) 25 for(int j = i*i;j <= maxn;j+=i) vis[j] = 1; 26 } 27 28 void solve( int x){ 29 int y = a[x]; 30 if(y == 1) return; 31 for(int i = 0;i < p.size();i++){ 32 int v = p[i]; 33 if(v == y) continue; 34 while(y){ 35 if(y % v) break; 36 y = y/v; 37 s.insert(v); 38 } 39 } 40 if(y > 1) s.insert(y); 41 } 42 43 void work(){ 44 if(s.size() < 2){ 45 puts("-1"); 46 return; 47 } 48 multiset<int>::iterator it; 49 50 it = s.begin(); 51 LL c1 = *it; 52 ++it; 53 LL c2 = *it; 54 printf("%I64d\n",c1*c2); 55 } 56 57 int main(){ 58 is(); 59 for(int i = 2;i <= maxn;i++){ 60 if(vis[i] == 0) p.push_back(i); 61 } 62 63 scanf("%d",&T); 64 while(T--){ 65 s.clear(); 66 memset(cnt,0,sizeof(cnt)); 67 scanf("%d",&n); 68 for(int i = 1;i <= n;i++) scanf("%d",&a[i]); 69 70 for(int i = 1;i <= n;i++){ 71 solve(i); 72 } 73 work(); 74 } 75 return 0; 76 }
hdu 5430 reflect
照题解的第一种办法写的
这样好慢啊,
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 7 int T,n; 8 9 int gcd(int a,int b){return (!b) ? a : gcd(b, a % b);} 10 11 int main(){ 12 scanf("%d",&T); 13 while(T--){ 14 scanf("%d",&n);n++; 15 16 int res = 0; 17 for(int i = 1;i <= n;i++){ 18 if(gcd(i,n) == 1) res++; 19 } 20 printf("%d\n",res); 21 } 22 return 0; 23 }
题解里面说到欧拉函数---
心想,咦,欧拉道路那不是图论里面的么----这题和图哪里有一毛钱关系啊啊啊啊-------
感谢神奇的度娘--
在数论,对正整数n,欧拉函数varphi(n)是少于或等于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名,它又称为Euler's totient function、φ函数、欧拉商数等。
抄了一个欧拉函数的模板
这样就31ms了
#include <cstdio> #include <cstdlib> using namespace std; #define N 1000005 int phi[N]; void eula(){ for(int i=1;i<=N;i++) phi[i] = i; for(int i=2;i<=N;i++) if(phi[i]==i) //如果phi[i]==i的话说明还没有进行过计算,为素数 //没有进行过计算,说明在当前i值之前(即比i小的数中)没有i的因数,所以i为素数 for(int j=i;j<=N;j+=i) phi[j]=phi[j]/i*(i-1);//将非素数进行计算 return; } int main(){ eula(); int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); printf("%d\n",phi[n+1]); } return 0; }