HDU6415 Rikka with Nash Equilibrium
找规律 + 大数
由于规律会被取模破坏,所以用了java
找出规律的思路是:
对于一个n*m的矩阵构造,我先考虑n*1的构造,很容易知道它是n!种方法。然后对于n*2的矩阵构造,就是在n*1的矩阵中新加入n个元素的排列组合,当然这里面一定会有非法的情况。通过打表可以暴力的搜出5*5以内的答案,所以我就可以知道从n*1的矩阵扩展到n*2的矩阵中有多少种非法组合(n <= 5 只知道小数据)。同理对于n*2扩展到n*3以后到n*(m-1)扩展到n*m的正确方案数和每次剔除的方案数就可以得到(小数据暴力得到)。然后发现规律 每次正确合法方案数:非法方案数 = i :(n-1);i从2迭代到m就可以得到答案。
java版本:
//package acm; import java.math.BigInteger; import java.awt.Container; import java.math.*; import java.math.BigInteger; import java.util.*; import org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID; public class Main { public static void main(String[] args) { Scanner cin=new Scanner(System.in); int t = cin.nextInt(); for(int i=1;i<=t;i++) { int n = cin.nextInt(); int m = cin.nextInt(); BigInteger k = cin.nextBigInteger(); if(n==1) { BigInteger ans = BigInteger.ONE; for(int j=1;j<=m;j++) { ans = ans.multiply(BigInteger.valueOf(j)); } ans = ans.mod(k); System.out.println(ans); } else { BigInteger ans1 = BigInteger.ONE; for(int j=1;j<=n;j++) { ans1 = ans1.multiply(BigInteger.valueOf(j)); } //System.out.println(ans1); for(int j=2;j<=m;j++) { BigInteger tt = BigInteger.valueOf(j*n); BigInteger temp = BigInteger.ONE; for(int kk=0;kk<n;kk++) { temp = temp.multiply(tt.subtract(BigInteger.valueOf(kk))); } ans1 = ans1.multiply(temp); ans1 = ans1.multiply(BigInteger.valueOf(j)).divide(BigInteger.valueOf(j+n-1)); } ans1 = ans1.mod(k); System.out.println(ans1); } } cin.close(); } }
这道题也可以用c++来通过对数进行拆分成质数的乘积来记录大数(因为保证了过程中除法都是整除)
c++版本:
#include <bits/stdc++.h> using namespace std; int cnt[10005],prime[10005],tag[70007]; void init(int n){ int cnt = 0; for(int i = 2;i <= n;++i){ if(!tag[i]) prime[cnt++] = i; for(int j = 0;j < cnt && prime[j] * i <= n;++j){ tag[i*prime[j]] = 1; if(i % prime[j] == 0) break; } } } vector<int> V[70005]; long long mod; long long power(long long a,long long k){ long long ret = 1; while(k){ if(k & 1) ret = ret * a % mod; a = a * a % mod; k >>= 1; } return ret; } int main() { init(7000); int T; cin >> T; for(int i = 0;i < 900;++i){ for(long long j = 1;j * prime[i] <= 7000;++j){ V[prime[i]*j].push_back(i); } } while(T--) { memset(cnt,0,sizeof(cnt)); int n,m; scanf("%d%d%lld",&n,&m,&mod); for(int i = n*m;i > 1;--i){ int siz = V[i].size(); int tmp = i; for(int j = 0;j < siz;++j){ while(tmp%prime[V[i][j]] == 0) tmp /= prime[V[i][j]],cnt[V[i][j]]++; } } for(int i = 2;i <= m;++i){ int tmp = n-1+i; int siz = V[tmp].size(); for(int j = 0;j < siz;++j){ while(tmp%prime[V[n-1+i][j]] == 0) tmp /= prime[V[n-1+i][j]],cnt[V[n-1+i][j]]--; } tmp = i; siz = V[tmp].size(); for(int j = 0;j < siz;++j){ while(tmp%prime[V[i][j]] == 0) tmp /= prime[V[i][j]],cnt[V[i][j]]++; } } long long ans = 1; for(int i = 0;i < 900;++i){ ans = ans * power(prime[i],cnt[i]) % mod; } cout << ans << endl; } return 0; }