• 【ZOJ】3380 Patchouli's Spell Cards


    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3957

    题意:m个位置,每个位置填1~n的数,求至少有L个位置的数一样的概率(1<=n,m,l<=100)

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    struct inum {
    	static const int N=205, MOD=10000;
    	int a[N], len;
    	inum(int x=0) { len=!x; memset(a, 0, sizeof a); while(x) a[++len]=x%MOD, x/=MOD; }
    	void fix() { while(len>1 && !a[len]) --len; }
    	void cln() { memset(a, 0, sizeof(int)*(len+1)); len=1; }
    	const bool operator<= (const inum &x) {
    		if(len<x.len) return 1;
    		if(len>x.len) return 0;
    		for(int i=len; i; --i)
    			if(a[i]<x.a[i]) return 1;
    			else if(a[i]>x.a[i]) return 0;
    		return 1;
    	}
    	inum operator+ (const inum &x) {
    		static inum ret;
    		ret.cln();
    		ret.len=max(len, x.len);
    		for(int i=1; i<=ret.len; ++i) {
    			ret.a[i]+=a[i]+x.a[i];
    			if(ret.a[i]>=MOD) ret.a[i+1]+=ret.a[i]/MOD, ret.a[i]%=MOD;
    		}
    		ret.len++;
    		ret.fix();
    		return ret;
    	}
    	inum operator- (const inum &x) {
    		static inum ret;
    		ret.cln();
    		for(int i=1; i<=len; ++i) {
    			ret.a[i]+=a[i]-x.a[i];
    			if(ret.a[i]<0) --ret.a[i+1], ret.a[i]+=MOD;
    		}
    		ret.len=len;
    		ret.fix();
    		return ret;
    	}
    	inum operator* (const inum &x) {
    		static inum ret;
    		ret.cln();
    		for(int i=1; i<=len; ++i)
    			for(int j=1; j<=x.len; ++j) {
    				ret.a[i+j-1]+=a[i]*x.a[j];
    				if(ret.a[i+j-1]>=MOD) ret.a[i+j]+=ret.a[i+j-1]/MOD, ret.a[i+j-1]%=MOD;
    			}
    		ret.len=len+x.len;
    		for(int i=1; i<=ret.len; ++i)
    			if(ret.a[i]>=MOD) ret.a[i+1]+=ret.a[i]/MOD, ret.a[i]%=MOD;
    		ret.fix();
    		return ret;
    	}
    	inum div2() {
    		static inum ret;
    		ret.cln();
    		for(int i=len, t=0; i; --i) {
    			t+=a[i];
    			ret.a[i]=t>>1;
    			t=(t&1)*MOD;
    		}
    		ret.len=len;
    		ret.fix();
    		return ret;
    	}
    	inum operator/ (const inum &x) {
    		static inum l, r, mid, ONE(1);
    		l=0; r=*this;
    		while(l<=r) {
    			mid=(l+r).div2();
    			if(mid*x<=*this) l=mid+ONE;
    			else r=mid-ONE;
    		}
    		return l-ONE;
    	}
    	inum operator% (const inum &x) { return *this-(*this/x)*x; }
    	static inum gcd(inum a, inum b) { return (b.len==1&&!b.a[1])?a:gcd(b, a%b); }
    	static inum pow(inum a, int n) {
    		inum x=1;
    		while(n) { if(n&1) x=x*a; a=a*a; n>>=1; }
    		return x;
    	}
    	void P() {
    		printf("%d", a[len]);
    		for(int i=len-1; i; --i)
    			printf("%.04d", a[i]);
    	}
    };
    
    const int N=105;
    inum C[N][N], d[N][N];
    int n, m, l;
    int main() {
    	C[0][0]=1;
    	for(int i=1; i<=100; ++i) {
    		C[i][0]=1;
    		for(int j=1; j<=i; ++j)
    			C[i][j]=C[i-1][j-1]+C[i-1][j];
    	}
    	while(~scanf("%d%d%d", &m, &n, &l)) {
    		if(l>m) { puts("mukyu~"); continue; }
    		d[0][0]=1; --l;
    		for(int i=1; i<=n; ++i)
    			for(int j=1; j<=m; ++j) {
    				d[i][j]=0; int t=min(j, l);
    				for(int k=0; k<=t; ++k)
    					d[i][j]=d[i][j]+d[i-1][j-k]*C[m-(j-k)][k];
    			}
    		inum up=0, down=0, gcd;
    		for(int i=1; i<=n; ++i) up=up+d[i][m];
    		down=inum::pow(n, m);
    		up=down-up;
    		gcd=inum::gcd(up, down);
    		down=down/gcd;
    		up=up/gcd;
    		up.P(); putchar('/'); down.P(); puts("");
    	}
    	return 0;
    }
    

      

    (麻麻我又码出了一个高精度模板QAQ感觉这一次封包得很好QAQ

    (反正超慢QAQ差点就tle了....6000+ms....

    首先本题超神!我忘记了补集转化....

    求至少L个位置的数一样的方案=总方案数-少于L个位置的数一样的方案数

    而后者非常好求...

    设$d[i][j]$表示前$i$种数在$m$个位置上填了$j$个的方案数

    $$d[i][j]=sum_{k=0}^{min(j, L-1)} d[i-1][j-k]C[m-(j-k)][k]$$

    那么$ans=frac{n^m-sum_{i=1}^{n} d[i][m]}{n^m}$

    由于输出分数形式...于是上高精度......

  • 相关阅读:
    微服务架构综述
    何为正确
    如何在github中写出自己的readme文件
    redhat中如何在一块网卡上创建多个虚拟IP
    Vim 编辑器与shell命令脚本
    管道符、重定向与环境变量
    linux常用命令
    Android性能优化总结
    HTTP 协议漫谈
    Zxing QRCode
  • 原文地址:https://www.cnblogs.com/iwtwiioi/p/4302081.html
Copyright © 2020-2023  润新知