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