• JZOJ.5230【NOIP2017模拟8.5】队伍统计


    Description

    现在有n个人要排成一列,编号为1->n 。但由于一些不明原因的关系,人与人之间可能存在一些矛盾关系,具体有m条矛盾关系(u,v),表示编号为u的人想要排在编号为v的人前面。要使得队伍和谐,最多不能违背k条矛盾关系(即不能有超过k条矛盾关系(u,v),满足最后v排在了u前面)。问有多少合法的排列。答案对10^9+7取模。
     

    Input

    输入文件名为count.in。
    第一行包括三个整数n,m,k。
    接下来m行,每行两个整数u,v,描述一个矛盾关系(u,v)。
    保证不存在两对矛盾关系(u,v),(x,y),使得u=x且v=y 。

    Output

    输出文件名为count.out。
    输出包括一行表示合法的排列数。
     

    Sample Input

    输入1:
    4 2 1
    1 3
    4 2
    
    输入2:
    10 12 3
    2 6
    6 10
    1 7
    4 1
    6 1
    2 4
    7 6
    1 4
    10 4
    10 9
    5 9
    8 10

    Sample Output

    输出1:
    18
    
    输出2:
    123120
     

    Data Constraint

    对于30%的数据,n<=10
    对于60%的数据,n<=15
    对应100%的数据,n,k<=20,m<=n*(n-1),保证矛盾关系不重复。

     n<=20,显然要状压DP,将排队的状态压成一个数来表示

    对于一个队伍状态S,令F[S][k]表示S状态违反了k条矛盾的合法方案数,则有

    F[S|2i-1][k+num(S&power[i])]=F[S|2i-1][k+num(S&power[i])]+F[S][k]

    其中i表示某个不在队伍的人,num(i)表示i在二进制下1的个数,power[i]表示必须排在i后面的人的情况。

    (实际操作中发现power[i]储存排在i后面的人的情况的时候运行速度远不及power[i]储存排在i前面的情况)

     1 #include<cstdio>
     2 using namespace std;
     3 const int qaq=1000000007;
     4 int f[1<<20][21],power[21],n,m,t;
     5 int main(){
     6     freopen("count.in","r",stdin);
     7     freopen("count.out","w",stdout);
     8     scanf("%d%d%d",&n,&m,&t);
     9     int u,v;
    10     for (int i=1;i<=m;i++){
    11         scanf("%d%d",&u,&v);
    12         power[u]|=1<<(v-1);        //power[v]|=1<<(u-1);
    13     }
    14     f[0][0]=1;
    15     for (int i=0;i<(1<<n);i++)
    16      for (int j=0;j<=t;j++)
    17          if (f[i][j])
    18              for (int k=1;k<=n;k++)
    19                  if ((i&(1<<(k-1)))==0){
    20                      int qwq=power[k]&i;    //int qwq=power[k]^(power[k]&i);
    21                      int sum=0;
    22                                 while (qwq){
    23                                  sum++;
    24                                  qwq&=(qwq-1);
    25                                 }
    26                      if (j+sum<=t){
    27                          f[i|(1<<(k-1))][j+sum]+=f[i][j];
    28                      if (f[i|(1<<(k-1))][j+sum]>=qaq) 
    29                         f[i|(1<<(k-1))][j+sum]%=qaq;
    30                     }
    31                  }
    32     int ans=0;
    33     for (int i=0;i<=t;i++)
    34      ans=(ans+f[(1<<n)-1][i])%qaq;
    35     printf("%d
    ",ans);
    36     return 0;
    37 }
    神奇的代码

    注意运算优先级,注意运算优先级,注意运算优先级!!!

  • 相关阅读:
    ubuntu qtcreator 硬件权限问题
    关于LuCi
    npm 使用记录
    ubuntu 下简单录音
    qthread 使用 signal 方法通信
    线程安全笔记一则
    ubuntu 设置 NAT 转发
    debian 中新建或调整 swap 空间
    关于 htonl 和 ntohl 的实现
    shell 调试手段总结
  • 原文地址:https://www.cnblogs.com/Lanly/p/7291379.html
Copyright © 2020-2023  润新知