第一周 8.31---9.6

---------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 }
View Code
 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 }
View Code

 

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 } 
View Code

 

--------- 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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

---------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 }
View Code

 

后来又想到爆搜,每个砝码可以放左边,右边,不放,应该搜得出来

然后我就这样去搜的

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 }
View Code

 

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 }
View Code

 

于是---后来,看到这场 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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

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 }
View Code

 

---------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 }
View Code

 

下午又变热了 ----

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 }
View Code

 

补一个搜题解的时候看到的另外的办法

想法还是和最小生成树的想法有一点像

先选择一个点 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 }
View Code

 

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 }
View Code

 

---------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 }
View Code

 

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 }
View Code

 搞懂一点点可行顶标了

因为,可行顶标是一个节点函数 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

-------做到这道题真是好怀念啊啊啊啊啊啊---

Good Bye 2014

记得那天晚上刚好是平安夜

宿舍在一起玩了一晚上

期待着下雪却没有下

吃了好多

还有好多苹果

然后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 }
View Code

 

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 }
View Code

 

---------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 }
View Code

 然后自己写的,是因为素数没有筛完,这样改一下,

 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 }
View Code

 

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 }
View Code

 

题解里面说到欧拉函数---

心想,咦,欧拉道路那不是图论里面的么----这题和图哪里有一毛钱关系啊啊啊啊-------

感谢神奇的度娘--

数论,对正整数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;
}
View Code

 

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值