zoukankan      html  css  js  c++  java
  • [补档][NOI 2008]假面舞会

    [NOI 2008]假面舞会

    题目 

      一年一度的假面舞会又开始了,栋栋也兴致勃勃的参加了今年的舞会。今年的面具都是主办方特别定制的。每个参加舞会的人都可以在入场时选择一个自己喜欢的面具。
    每个面具都有一个编号,主办方会把此编号告诉拿该面具的人。为了使舞会更有神秘感,主办方把面具分为k (k≥3)类,并使用特殊的技术将每个面具的编号标在了面具上,只有戴第i 类面具的人才能看到戴第i+1 类面具的人的编号,戴第k 类面具的人能看到戴第1 类面具的人的编号。
      参加舞会的人并不知道有多少类面具,但是栋栋对此却特别好奇,他想自己算出有多少类面具,于是他开始在人群中收集信息。
      栋栋收集的信息都是戴第几号面具的人看到了第几号面具的编号。如戴第2号面具的人看到了第5 号面具。栋栋自己也会看到一些编号,他也会根据自己的面具编号把信息补充进去。由于并不是每个人都能记住自己所看到的全部编号,因此,栋栋收集的信 息不能保证其完整性。现在请你计算,按照栋栋目前得到的信息,至多和至少有多少类面具。由于主办方已经声明了k≥3,所以你必须将这条信息也考虑进去。

    INPUT

      输入文件第一行包含两个整数n, m,用一个空格分隔,n 表示主办方总共准备了多少个面具,m 表示栋栋收集了多少条信息。
    接下来m 行,每行为两个用空格分开的整数a, b,表示戴第a 号面具的人看到了第b 号面具。相同的数对a, b 在输入文件中可能出现多次。

    OUTPUT

      输出文件包含两个数,第一个数为最大可能的面具类数,第二个数为最小可能的面具类数。如果无法将所有的面具分为至少3 类,使得这些信息都满足,则认为栋栋收集的信息有错误,输出两个-1。

    SAMPLE

    INPUT1

    6 5
    1 2
    2 3
    3 4
    4 1
    3 5

    OUTPUT1

    4 4

    INPUT2

    3 3

    1 2

    2 1
    2 3

    OUTPUT2

    -1 -1

    解题报告

      当时考试的时候,一看这种带顺序的类似图论的奇怪东西,就想到了拓扑排序
      然后......
      并不会打拓扑啊QAQ,于是打了个奇(chun)奇(dao)怪(bao)怪(zha)的dfs,好像拿了个特判的-1 -1的分QAQ
      正解仍然是dfs
      由题目可知,从一个点连出去的点标号一样,几个点指向同一个点,标号也肯定一样。而且,有一句很重要的话:
      戴第k 类面具的人能看到戴第1 类面具的人的编号。
      那么如果我们找到了环,并将所有环的GCD找出来,我们就找到了最大值。正确性显然= =
      如果没有环呢?
      显然我们还可以找到链,而链则不会受到上面那个条件的制约,我们就可以很轻松的解决这个问题啦。
      然而我们似乎忘记了一个很神奇的东西= =
      当我们遇到有各种方向边的环时,显然通过上面的证明,会有第一个点有多个不同标号的情况,这是不可能的,所以,只能看作是不停的由第k个点看第一个点的特殊情况。
      如何处理?
      很简单,设某个方向边组成的那半个环为ax+k=b的循环,另一个方向边组成的那半个环为cx+k=b的循环。(这里的循环指从第一个点一直走到第k个点再走回第一个点)。显然环是要一样大的,而多出n个环数的点数也应是一样大的(不然起点或终点就会有不止一个标号)。
      所以,我们只需建双向边,正边权值1,反边权值-1,最后取个绝对值,就可当正常环看待了(正确性显然= =)

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 using namespace std;
      5 inline int read(){
      6     int sum(0);
      7     char ch(getchar());
      8     while(ch<'0'||ch>'9')
      9         ch=getchar();
     10     while(ch>='0'&&ch<='9'){
     11         sum=sum*10+ch-'0';
     12         ch=getchar();
     13     }
     14     return sum;
     15 }
     16 struct edge{
     17     int s,e,n,w;
     18 }a[2000001];
     19 int pre[100001],tot;
     20 inline void insert(int s,int e,int w){
     21     a[++tot].s=s;
     22     a[tot].e=e;
     23     a[tot].w=w;
     24     a[tot].n=pre[s];
     25     pre[s]=tot;
     26 }
     27 inline void swp(int &a,int &b){
     28     a^=b;
     29     b^=a;
     30     a^=b;
     31 }
     32 /*inline int gcd(int a,int b){
     33     //cout<<a<<' '<<b<<endl;
     34     if(a==0)
     35         return b;
     36     if(b==0)
     37         return a;
     38     int i,j;
     39     for(i=0;0==(a&1);i++)
     40         a>>=1;
     41     for(j=0;0==(b&1);j++)
     42         b>>=1;
     43     if(j<i)
     44         i=j;
     45     while(1){
     46         if(a<b)
     47             swp(a,b);
     48         if(0==(a-=b))
     49             return b<<i;
     50         while(a&1)
     51             a>>=1;
     52     }
     53 }*/
     54 inline int gcd(int a,int b){
     55     if(a==0)
     56         return b;
     57     if(b==0)
     58         return a;
     59     return a%b?gcd(b,a%b):b;
     60 }
     61 inline int jdz(int x){
     62     return x>=0?x:-x;
     63 }
     64 inline int my_min(int a,int b){
     65     return a<b?a:b;
     66 }
     67 inline int my_max(int a,int b){
     68     return a>b?a:b;
     69 }
     70 int n,m;
     71 bool vis[100001]={0};
     72 int f[100001]={0};
     73 int mx,mn;
     74 int circle(0),ans(0);
     75 inline void dfs(int u,int cnt){
     76     if(vis[u])
     77         return;
     78     f[u]=cnt;vis[u]=1;
     79     mx=my_max(mx,cnt);
     80     mn=my_min(mn,cnt);  
     81     for(int i=pre[u];i!=-1;i=a[i].n){
     82         int e(a[i].e);
     83         if(vis[e]){
     84             int cir(jdz(cnt-f[e]+a[i].w));
     85             if(cir){
     86                 if(circle==0)
     87                     circle=cir;
     88                 else
     89                     circle=gcd(circle,cir);
     90             }
     91         }
     92         else
     93             dfs(e,cnt+a[i].w);
     94     }
     95 }
     96 int main(){
     97 //  freopen("party2008.in","r",stdin);
     98 //  freopen("party2008.out","w",stdout);
     99     memset(pre,-1,sizeof(pre));
    100     n=read(),m=read();
    101     for(int i=1;i<=m;i++){
    102         int x(read()),y(read());
    103         insert(x,y,1);
    104         insert(y,x,-1);
    105     }
    106     for(int i=1;i<=n;i++)
    107         if(!vis[i]){
    108             mx=-0x7fffffff;
    109             mn=0x7fffffff;
    110             dfs(i,0);
    111             ans+=mx-mn+1;
    112         }
    113     if(circle==0){
    114         if(ans<3){
    115             printf("-1 -1");
    116             return 0;
    117         }
    118         else{
    119             printf("%d %d",ans,3);
    120             return 0;
    121         }
    122     }
    123     else{
    124         if(circle<3){
    125             printf("-1 -1");
    126             return 0;
    127         }
    128         else{
    129             printf("%d ",circle);
    130             int gg(0);
    131             for(int i=3;i<=circle;i++){
    132                 if(circle%i==0){
    133                     gg=i;
    134                     break;
    135                 }
    136             }
    137             if(gg==0)
    138                 printf("%d",circle);
    139             else
    140                 printf("%d",gg);
    141         }
    142     }
    143 }  
    View Code

    ps:一直在WA,最后发现是GCD打错了= =  

  • 相关阅读:
    Windows_10 系统封装
    leetcode-75 颜色分类
    leetcode-922 按奇偶排序数组 II
    leetcode-905 按奇偶数排序
    UVA-10827 环面上的最大子矩阵和
    leetcode918 环形最大子数组
    leetcode-85 最大矩形
    leetcode-84 柱状图中的最大矩形
    leetcode-221 最大正方形
    leetcode-713 乘积小于k的数组
  • 原文地址:https://www.cnblogs.com/hzoi-mafia/p/7275724.html
Copyright © 2011-2022 走看看