Codeforces Round #383 (Div. 1)

A:

题目大意:给出一个有向图(n<=100),每个点的出度都为1,求最小的t,使得任意两点x,y,如果x走t步后能到y,那么y走t步后到x。

 

题解:

首先每个点应该都在一个环上,否则无解。

对于大小为k的奇环上的点,满足要求的最小的t是k.

对于大小为k的偶环上的点,满足要求的最小的t是k/2.

对于每个环求最小公倍数即可。  数据范围很小,直接暴力求环就可以了。

 

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <map>
 8 #include <cstdlib>
 9 #include <set>
10 using namespace std;
11 
12 #define X first
13 #define Y second
14 #define Mod 1000000007
15 #define N 110
16 typedef long long ll;
17 typedef pair<int,int> pii;
18 
19 int n;
20 int a[N];
21 bool vis[N];
22 
23 ll gcd(ll x,ll y)
24 {
25     ll tmp;
26     while (y)
27     {
28         tmp=x%y;
29         x=y;y=tmp;
30     }
31     return x;
32 }
33 
34 ll lcm(ll x,ll y)
35 {
36     return x/gcd(x,y)*y;
37 }
38 
39 int main()
40 {
41     //freopen("in.in","r",stdin);
42     //freopen("out.out","w",stdout);
43     
44     scanf("%d",&n);
45     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
46     ll ans=1;
47     for (int i=1;i<=n;i++)
48     {
49         int t=i,c=0;
50         memset(vis,0,sizeof(vis));
51         do
52         {
53             vis[t]=true;
54             c++,t=a[t];
55         }while(!vis[t]);
56         if (t==i)
57         {
58             if (!(c&1)) c>>=1;
59             ans=lcm(ans,c);
60         }
61         else 
62         {
63             printf("-1\n");
64             return 0;
65         }
66     }
67     printf("%d\n",ans);
68     return 0;
69 }
View Code

 

 

B:

题目大意: 你要从n个客人中邀请一些人来参加派对, 每个客人有一个w和b。要求在邀请的客人的w之和不能超过W的情况下,使得客人的b的和最大。 n,W<=1000

有一些客人是朋友关系,且满足传递性,对于一些朋友,要么全部邀请,要么最多邀请其中的一个。

 

题解: 

考虑DP。 首先用并查集搞出朋友关系的集合,dp[i][j]表示考虑前i个集合,w的和为j的最优解。

转移的时候 要么把整个第i个集合取过来,要么枚举其中的一个元素取过来。

考虑复杂度: 对于第k个人,假设他在第i个集合,那么他在dp[i][0.....W]的时候都用来转移了一次。

所以复杂度是O(nW).

 

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <map>
 8 #include <cstdlib>
 9 #include <set>
10 using namespace std;
11 
12 #define X first
13 #define Y second
14 #define Mod 1000000007
15 #define N 1010
16 #define M 10000010
17 typedef long long ll;
18 typedef pair<int,int> pii;
19 
20 
21 int n,m,w;
22 int a[N],b[N],father[N],id[N];
23 int s1[N],s2[N];
24 int dp[N][N];
25 
26 vector<int> g[N];
27 
28 int Find(int x)
29 {
30     if (father[x]==x) return x;
31     father[x]=Find(father[x]);
32     return father[x];
33 }
34 
35 void Merge(int x,int y)
36 {
37     x=Find(x),y=Find(y);
38     if (x==y) return ;
39     father[x]=y;
40 }
41 
42 int main()
43 {
44     //freopen("in.in","r",stdin);
45     //freopen("out.out","w",stdout);
46     
47     scanf("%d%d%d",&n,&m,&w);
48     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
49     for (int i=1;i<=n;i++) scanf("%d",&b[i]),father[i]=i;
50     int x,y;
51     for (int i=1;i<=m;i++)
52     {
53         scanf("%d%d",&x,&y);
54         Merge(x,y);
55     }
56     int t=0;
57     for (int i=1;i<=n;i++) if (Find(i)==i) id[i]=++t;
58      for (int i=1;i<=n;i++) 
59     {
60          int x=id[Find(i)];
61          g[x].push_back(i);
62          s1[x]+=a[i];
63          s2[x]+=b[i];
64     }
65     
66     int ans=0; 
67     for (int i=1;i<=t;i++)
68     {
69         for (int j=0;j<=w;j++)
70         {
71             dp[i][j]=dp[i-1][j];
72             if (j>=s1[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-s1[i]]+s2[i]);
73             for (int k=0;k<g[i].size();k++)
74             {
75                 if (j>=a[g[i][k]]) dp[i][j]=max(dp[i][j],dp[i-1][j-a[g[i][k]]]+b[g[i][k]]);
76             }
77             if (i==t) ans=max(ans,dp[i][j]);
78         }
79     }
80     printf("%d\n",ans);
81     
82     return 0;
83 }
View Code

 

 

C:

题目大意:n对男女(2n个人)围成一圈,要给他们黑白染色,要求任意三个相邻的人颜色不能完全一样。  第i对情侣分别是ai和bi,他们的颜色要不一样。 n<=100000.

 

题解:

比赛的时候没有想出来...下面是官方题解:

首先给ai和bi连边,然后给2*i-1和2*i 连边,可以证明这个图是二分图,做一次染色就好啦。

证明:

记给ai和bi连的边为A类边,2*i-1和2*i 连的边为B类边。

由于一个人不可能和多个人是男女朋友关系,所以对于每个点有且只有1条A类边和它相连,同时有且只有1条B类边。

考虑任意一个环。 对于环上的边,只能是AB类边交替,否则就会有2条A类边或者2条B类边和同一个点相连。

因此环不可能是奇环。 故这个图是二分图。

 

代码:

 1  #include <iostream>
 2 #include <cstdio>
 3 #include <cmath>
 4 #include <cstring>
 5 #include <algorithm>
 6 #include <vector>
 7 #include <map>
 8 #include <cstdlib>
 9 #include <set>
10 #include <queue>
11 using namespace std;
12 
13 #define X first
14 #define Y second
15 #define Mod 1000000007
16 #define N 200110
17 #define M 200110
18 
19 typedef long long ll;
20 typedef pair<int,int> pii;
21 
22 const ll INF=4e18;
23 
24 int n;
25 vector<int> g[N];
26 int color[N],a[N],b[N];
27 
28 bool Dfs(int x,int c)
29 {
30     color[x]=c;
31     for (int i=0;i<g[x].size();i++)
32     {
33         int y=g[x][i];
34         if (!color[y] && !Dfs(y,3-c)) return false; 
35         else if (color[y]==color[x]) return false;
36     }
37     return true;
38 }
39 
40 int main()
41 {
42     //freopen("in.in","r",stdin);
43     //freopen("out.out","w",stdout);
44 
45     scanf("%d",&n);
46     for (int i=1;i<=n;i++)
47     {
48         int x,y;
49         scanf("%d%d",&x,&y);
50         a[i]=x,b[i]=y;
51         g[x].push_back(y);
52         g[y].push_back(x);
53     }
54     for (int i=1;i<=n;i++) g[2*i-1].push_back(2*i),g[2*i].push_back(2*i-1);
55     for (int i=1;i<=2*n;i++) if (!color[i]) Dfs(i,1);
56     for (int i=1;i<=n;i++) printf("%d %d\n",color[a[i]],color[b[i]]);
57     return 0;
58 }
View Code

 

posted @ 2016-12-08 12:07  lzw4896s  阅读(244)  评论(0编辑  收藏  举报