[DP]Mixing Chemicals

题目描述

实验室有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

分析

一开始以为是树形DP,值通过祖父关系传递
后来想了想,可以转化成黑白染色问题:相邻的点若染同色,则需要两个盒子,不同则可以共用一个
然后动态转移方程易得

#include <iostream>
#include <cstdio>
#include <memory.h>
#define rep(i,a,b) for (i=a;i<=b;i++)
typedef long long ll;
const ll MOD=1e9+7;
using namespace std;
int t,n,fa[101],b[101],circles,cirnow;
ll f[101][2],ans,k;

int main() {
    int i;
    scanf("%d",&t);
    while (t--) {
        scanf("%d%lld",&n,&k);
        f[1][0]=k-1;
        f[0][1]=1;
        rep(i,2,n) {
            f[i][0]=(f[i-1][1]*(k-1)+f[i-1][0]*(k-2))%MOD;
            f[i][1]=f[i-1][0]%MOD;
        }
        rep(i,0,n-1) scanf("%d",&fa[i]);
        memset(b,0x3f,sizeof(b));
        ans=1;circles=0;
        rep(i,0,n-1)
        if (b[i]>n-1) {
            int j;
            for (j=i;b[j]>n-1;j=fa[j]) b[j]=i;
            if (b[j]!=i) continue;
            cirnow=0;
            int l=j;
            do {
                cirnow++;
                j=fa[j];
            }
            while (j!=l);
            ans=ans*f[cirnow][1]%MOD*k%MOD;
            circles+=cirnow;
        }
        rep(i,1,n-circles) ans=ans*(k-1)%MOD;
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/ssl_qyh0ice/article/details/81105045