acmlive7040容斥原理
2015-08-21 22:55
169 查看
题意:长度为 N 的序列,M 种颜色,要求用恰好 K 种颜色为序列染色,且相邻元素颜色不同,求方案数
容易想到分两步处理,第一步求组合数 C(M, K),从 M 种颜色中确定 K 个要用的。然后将问题转化成用恰好 K 种颜色,给长度为 N 的序列染色,要求相邻两两不同。
一个计数方案:K(K−1)^n−1,但是这是有问题的,<= K 个颜色被使用过。
假如k种颜色已经选好C(m,k)种方案。
记f(x) 为x种可选颜色结果。f(x)=x(x−1)^n−1
容斥一下: f(k) - C(k,k-1)*f(k-1) + C(k,k-2)f(k-2)-……..
所以结果为:
C(m,k) * [ f(k) - C(k,k-1)*f(k-1) + C(k,k-2)f(k-2)-…….. ]
容易想到分两步处理,第一步求组合数 C(M, K),从 M 种颜色中确定 K 个要用的。然后将问题转化成用恰好 K 种颜色,给长度为 N 的序列染色,要求相邻两两不同。
一个计数方案:K(K−1)^n−1,但是这是有问题的,<= K 个颜色被使用过。
假如k种颜色已经选好C(m,k)种方案。
记f(x) 为x种可选颜色结果。f(x)=x(x−1)^n−1
容斥一下: f(k) - C(k,k-1)*f(k-1) + C(k,k-2)f(k-2)-……..
所以结果为:
C(m,k) * [ f(k) - C(k,k-1)*f(k-1) + C(k,k-2)f(k-2)-…….. ]
import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.StreamTokenizer; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.NavigableSet; import java.util.PriorityQueue; import java.util.Queue; import java.util.Scanner; import java.util.Set; import java.util.SortedSet; import java.util.Stack; import java.util.StringTokenizer; import java.util.TreeSet; import org.omg.CORBA.Object; public class Main { public static void main(String[] args) throws IOException{ StreamTokenizer cin = new StreamTokenizer(new BufferedInputStream(System.in)); InputReader in = new InputReader(System.in) ; PrintWriter out = new PrintWriter(System.out) ; int t = in.nextInt() ; for(int i = 1 ; i <= t ; i++){ out.print("Case #" + i + ": ") ; new Task().solve(in, out) ; //out.flush() ; } out.flush() ; } } class Task{ static final long mod = 1000000007L ; int n , m , k ; long[] C ; static long[] niyuan = new long[1000001] ; static{ for(int i = 1 ; i <= 1000000 ; i++) niyuan[i] = pow(i , (int)mod - 2) % mod ; } static long pow(int x , int y){ long s = 1L , t = (long) x ; for(; y > 0 ; y >>= 1){ if((y & 1) > 0){ s = (s * t) % mod ; } t = (t * t) % mod ; } return s ; } void getC(int N){ C[0] = 1L ; for(int i = 1 ; i <= k ; i++){ C[i] = C[i-1] * niyuan[i] % mod ; C[i] = C[i] * (N+1-i) % mod ; } } long doK(int K){ return K * pow(K-1 , n-1) % mod ; } public void solve(InputReader in , PrintWriter out) throws IOException{ n = in.nextInt() ; m = in.nextInt() ; k = in.nextInt() ; if(n == 1 && k == 1){ out.println(m) ; return ; } if(n == 1){ out.println(0) ; return ; } C = new long[k+1] ; getC(k) ; long sum = 0L ; long sig = 1 ; for(int i = k ; i >= 2 ; i--){ sum = ( (sum + sig * C[i] * doK(i) ) % mod + mod) % mod ; sig = -sig ; } getC(m) ; out.println(C[k] * sum % mod) ; } } class InputReader{ public BufferedReader reader; public StringTokenizer tokenizer; public InputReader(InputStream stream){ reader = new BufferedReader(new InputStreamReader(stream), 32768) ; tokenizer = null ; } public String next(){ while(tokenizer == null || ! tokenizer.hasMoreTokens()){ try{ tokenizer = new StringTokenizer(reader.readLine()); }catch (IOException e) { throw new RuntimeException(e); } } return tokenizer.nextToken(); } public int nextInt() { return Integer.parseInt(next()); } public long nextLong() { return Long.parseLong(next()); } }
相关文章推荐
- Fragment讲解
- 大数据处理技术
- 苹果官方 Crash文件分析方法 (iOS系统Crash文件分析方法)
- 在JMeter测试计划中如何控制业务比例
- 【LeetCode】(67)Add Binary (Easy)
- Python Elasticsearch api
- iOS开发之网络篇-各种网络状态码
- NBUT 1456 Orianna (DP)
- uva 1453 - Squares(旋转卡壳)
- 黑马程序员——OC的内存管理——ARC
- linux下50个常用命令
- Libevent源码分析-timer和signal处理
- ssh常见错误
- 创建mysql数据库并指定编码
- 傻瓜都能看懂的网络流ek算法(poj1273)
- 【C++】万年历(时间计数器)
- Android的Service组件
- 要有被打断仍能够继续学习的能力
- 删除数据库mysql
- uva 10256 - The Great Divide(凸包)