zoukankan      html  css  js  c++  java
  • Mixing Chemicals

    题目描述

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

    输入

    第一行一个整数T,表示有T组测试数据。
    对于每组数据
    第一行两个整数n,k
    第二行n个整数表示c[i] 

    输出

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

    样例输入

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

    样例输出

    6
    12

    数据范围限制

    【数据范围】
     1<=T<=50
     1<=n<=100
     2<=k<=1000
    0<=c i <n,i≠c[i]
    对于30%的数据T,n,k<=50

     爆零。。。

    题目来自 BestCoder Round #71 (div.2)

    官方题解:

    根据药品之间的相互关系,我们可以构建一张图,我们对相互会发生反应的药品连边  //连边表示他们两个化学药品不能在一起

    这个图的特征,是一个环加上一些“树”(可能有多个联通块)//如这么一个图

    一个环(1,2,3,4,5……,n)m染色的方案数:递推,设第一个点颜色为1

    f[I,1]表示i点颜色为1的种数,f[I,0]为颜色不为1时(不考虑n与1颜色不同)

    则F[I,0]=f[i-1,0]*(m-2)+f[i-1,1]*(m-1),F[I,1]=f[i-1,0]

    那么方案数为f[n,0]*m

    一个根节点颜色固定且有k个孩子的树的m染色的方案数={(m-1)}^{k}(m?1)?k??,因为每个点的颜色只要与他的父亲颜色不同,即m-1种

    因为乘法原理,一个联通块的方案数=环方案数*以环上每个点为根的树的积。多个联通块,再连乘即可。

     1 {
     2     by @bobble !
     3                     2017-1-21
     4 }
     5 program mix;
     6 const
     7   inf='mix.in';
     8   outf='mix.out';
     9   wtf=1000000007;
    10 var
    11    n,k,j,i,t:longint;
    12    apple,tmp,ans,u,ltk:int64;
    13    a:array[0..100] of longint;
    14    b:array[0..100] of longint;
    15    boo:boolean;
    16    f:array[0..100,0..1]  of int64;
    17 
    18 begin
    19   assign(input,inf);
    20   assign(output,outf);
    21   reset(input); rewrite(output);
    22 
    23   readln(t);
    24  for j:= 1 to t do
    25  begin
    26    fillchar(a,sizeof(a),false);
    27    fillchar(b,sizeof(b),0);
    28 
    29    readln(n,k);
    30    f[1,0]:=k-1;    f[0,1]:=1;
    31      for i:= 2 to n do
    32        begin
    33           f[i,0]:=(f[i-1,1]*(k-1)+f[i-1,0]*(k-2)) mod wtf;
    34           f[i,1]:=(f[i-1,0]) mod wtf ;
    35        end;
    36    for i:= 0 to n-1 Do
    37    begin
    38      read(a[i]);
    39      b[i]:=233;
    40    end;
    41 
    42    apple:=0;
    43    ans:=1;
    44    for i:= 0 to n-1 do
    45      if b[i]=233 then
    46      begin
    47            tmp:=i;
    48            while b[tmp]=233 do
    49              begin
    50                  b[tmp]:=i;
    51                  tmp:=a[tmp];
    52              end;
    53            if b[tmp]<>i then continue;
    54            ltk:=0;  u:=tmp;
    55         repeat
    56           inc(ltk);
    57           tmp:=a[tmp];
    58         until tmp=u;
    59 
    60            ans:=ans*(f[ltk,1]*k mod wtf) mod wtf;
    61         apple:=apple+ltk;
    62      end;
    63      n:=n-apple;
    64      for i:= 1 to n do
    65        ans:=ans*(k-1) mod wtf;
    66     writeln(ans);
    67  end;
    68 
    69   close(input);
    70   close(output);
    71 end.
  • 相关阅读:
    【Vegas原创】更改Linux系统默认语言
    【Vegas原创】RMAN还原一个损坏的user表空间的数据文件
    【Vegas原创】VMWare虚拟的Linux系统下,安装VMWare的增强工具
    【Vegas原创】在线修改redo.log文件的大小
    【Vegas原创】DB和DG的切换
    [工程备案]linux平台,用第三方开源库进行网页抽取和数据解析
    各种流派的正则表达式说明以及shell正则表达式
    python 自然语言处理编码转换
    工作总结2013
    linux上配置boost手记
  • 原文地址:https://www.cnblogs.com/bobble/p/6337456.html
Copyright © 2011-2022 走看看