zoukankan      html  css  js  c++  java
  • [dp] Jzoj P3460 Mixing Chemicals

    Description

    实验室有n瓶化学药品,编号为0到n-1,你知道第i瓶只有和第c[i]瓶放在一起才会发生爆炸。为了整理实验室,你需要将他们装进k个丌同的盒子里。显然,为了你的生命安全,你丌能把两瓶会造成爆炸的药品放进同一个箱子。你希望计算出有多少中丌同的方案。为了降低难度,你只需要将答案mod 1000000007。
     

    Input

    第一行一个整数T,表示有T组测试数据。

    对于每组数据

    第一行两个整数n,k

    第二行n个整数表示c[i]

    Output

    对于每组数据输出一行一个整数。
     

    Sample Input

    3
    3 3
    1 2 0
    4 3
    1 2 0 0
    3 2
    1 2 0

    Sample Output

    6
    12
    0
     

    Data Constraint

    1<=T<=50 1<=n<=100 2<=k<=1000 0<Ci <n ,i≠c[i]

    对于30%的数据T,n,k<=50

    题解

    • 题目大意:给n瓶化学药品和k个盒子,每瓶化学药品和一瓶化学药品不能放在一个盒子里,求放化学药品的方案数
    • 我们可以将不能放在同一个盒子的两瓶化学药品连一条边,那么就形成了一个图,而且每个点的出都只有1
    • 那么考虑一下染色,一条边的两个点不能染成同一种颜色
    • 其实这样的话,就可以设f[i][0/1]为第i个点,染0色或1色的方案数
    • f[i][0]=(f[i-1][1]*(k-1)+f[i-1][0]*(k-2))%mo
    • f[i][1]=f[i][0]
    • 这个可以预处理出来
    • 然后我们将每个点在哪个环求出来,在求出连通块的个数,然后ans=ans* (f[lt,1]*k%mo)%mo lt为当前循环的搜到的连通块的个数
    • 求出将每个连通块的填颜色的个数相乘就求出ans

    代码

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cstring>
     4 using namespace std;
     5 const int inf=1000000000,mo=1000000007;
     6 long long ans,a[110],d[110],tot,num,f[110][3];
     7 int n,k,t;
     8 int main()
     9 {
    10     for (scanf("%d",&t);t;t--)
    11     {
    12         memset(a,0,sizeof(a)); memset(d,0,sizeof(d)); memset(f,0,sizeof(f));
    13         scanf("%d%d",&n,&k);
    14         for (int i=0;i<=n-1;i++) 
    15         {
    16             scanf("%lld",&a[i]);
    17             d[i]=inf;
    18         }
    19         f[0][1]=1; f[1][0]=k-1;
    20         for (int i=2;i<=n;i++)
    21         {
    22             f[i][0]=(f[i-1][1]*(k-1)+f[i-1][0]*(k-2))%mo;
    23             f[i][1]=f[i-1][0];
    24         }
    25         num=0; ans=1;
    26         for (int i=0;i<=n-1;i++)
    27             if (d[i]==inf)
    28             {
    29                 int x=i;
    30                 while (d[x]==inf) d[x]=i,x=a[x];
    31                 if (d[x]!=i) continue;
    32                 int y=x; tot=1; x=a[x];
    33                 while (x!=y) tot++,x=a[x];
    34                 ans=ans*(f[tot][1]*k%mo)%mo;
    35                 n-=tot;
    36             }
    37         for (int i=1;i<=n;i++) (ans*=(k-1))%=mo;
    38         printf("%lld
    ",ans);
    39     }
    40 }
  • 相关阅读:
    dtoi2680「SDOI2016」生成魔咒
    dtoi2679「SDOI2016」游戏
    dtoi2678「SDOI2016」数字配对
    dtoi2677「SDOI2016」储能表
    dtoi4545「HNOI2016」树
    dtoi4543「HNOI2016」最小公倍数
    dtoi4544「HNOI2016」网络
    dtoi4548「HNOI2016」大数
    ts定义数组对象
    RN项目ios本地模拟机无法加载本地图片的解决方案
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9329661.html
Copyright © 2011-2022 走看看