zoukankan      html  css  js  c++  java
  • 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
    ");
    64             return 0;
    65         }
    66     }
    67     printf("%d
    ",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
    ",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
    ",color[a[i]],color[b[i]]);
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    [转]AsyncTask的用法
    [转]Android Service学习之本地服务
    强制页面运行于IE8模式下
    标签分类
    获取元素的文本
    遍历节点的API
    为IE的javascript提速
    我的选择器 获得经过标记的没有重复的tagName等于tag的元素集
    kangax 的javascript谜题
    自动执行函数
  • 原文地址:https://www.cnblogs.com/vb4896/p/6144421.html
Copyright © 2011-2022 走看看