ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

专项测试 数学2

2022-01-07 17:36:51  阅读:149  来源: 互联网

标签:专项 ch return limits int sum 数学 测试 binom


A. 猜拳游戏

可以分成两部分解决

一部分解决每一轮赢的概率,一部分解决最后获胜的概率

先看第一部分,发现每一轮平局不影响结果,于是忽略他,只考虑输赢的情况

设 \(p,r\) 分别为原来赢和输的概率,设 \(q=\frac{p}{p+r}\) 即现在每轮赢的概率

变化一下形式 \(\frac{p}{p+r}=1-\frac{r}{p+r}=1-\frac{1}{1+\frac{p}{r}}\)

于是最大化 \(\frac{p}{r}\) 即可,可以使用分数规划

二分一个 \(mid\) 和当前的 \(\frac{p}{r}\) 比较

\(\frac{p}{r}>mid \rightarrow p>mid\times r \rightarrow p-mid\times r>0\)

于是假设 \(A\) 赢一轮 \(+1\) 分 \(B\) 赢一轮 \(-mid\) 分

从后往前 \(dp\) ,设 \(f_{i,j}\) 表示第 \(i\) 轮赢比输多 \(j\) 局的最大 \(p-mid\times r\)

然后一下看 \(f_{0,0}\) 是否大于 \(0\)

\(f_{n,x}\) 边界

  1. \(x>0\) 为 \(1\)

  2. \(x<0\) 为 \(-mid\)

  3. \(x=0\) 为 \(0\)

再看第二部分,发现 \(m1+m2\) 的数量级很小于是直接高斯消元

\(a_i\) 表示多赢 \(i\) 轮的概率 \(a_i=a_{i-1}\times q+a_{i+1}\times (1-q)\)

注意一下边界

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define eps 1e-8
#define O 1000
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m1,m2;
double a[1010][3],f[1010][2010],q;
inline bool check(double mid){
	double r1,r2,r3;
	memset(f,0,sizeof(f));
	for(int i=-n;i<=n;i++){if(i>0) f[n][i+O]=1;if(i==0) f[n][i+O]=0;if(i<0) f[n][i+O]=-mid;}
	for(int i=n;i;i--) for(int j=-i+1;j<=i-1;j++){
		r1=f[i][j+1+O]*a[i][1]+f[i][j+O]*a[i][0]+f[i][j-1+O]*a[i][2];//+a[i][1]-mid*a[i][2];
		r2=f[i][j+1+O]*a[i][2]+f[i][j+O]*a[i][1]+f[i][j-1+O]*a[i][0];//+a[i][2]-mid*a[i][0];
		r3=f[i][j+1+O]*a[i][0]+f[i][j+O]*a[i][2]+f[i][j-1+O]*a[i][1];//+a[i][0]-mid*a[i][1];
		f[i-1][j+O]=max({r1,r2,r3});
	}
	return f[0][0+O]>0;
}
namespace G{
	double mp[210][210];//+m2
	inline void gaussbuild(){
		memset(mp,0,sizeof(mp));
		for(int i=1;i<=m1+m2+1;i++) mp[i][i]=1;
		for(int i=1;i<m1+m2;i++) mp[i][i+1]=-(1-q);
		for(int i=3;i<=m1+m2+1;i++) mp[i][i-1]=-q;
		mp[m2+1][m1+m2+2]+=1;
	}
	inline double gauss(int n){
		int maxp;double div,mx;
		for(int i=1;i<=n;i++){
			maxp=i,mx=mp[i][i];
			for(int j=i+1;j<=n;j++) if(fabs(mp[j][i])>mx) maxp=j,mx=fabs(mp[j][i]);
			if(i!=maxp) swap(mp[i],mp[maxp]);
			div=mp[i][i];
			for(int j=1;j<=n+1;j++) mp[i][j]/=div;
			for(int j=1;j<=n;j++){
				if(i==j) continue;
				if(mp[j][i]==0) continue;
				div=mp[j][i]/mp[i][i];
				for(int k=1;k<=n+1;k++) mp[j][k]=mp[j][k]-div*mp[i][k];
			}
		}
		return mp[n][n+1];
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	while(1){
		n=read(),m1=read(),m2=read();if(!n) break;
		for(int i=1;i<=n;i++) a[i][0]=read()/100.0,a[i][2]=read()/100.0,a[i][1]=read()/100.0;
		double l=0,r=10000;
		while(r-l>eps){
			double mid=(l+r)/2;
			if(check(mid)) l=mid;
			else r=mid;
		}
		if(fabs(10000-l)<eps) q=1.00000;
		else q=1.0-1.0/(l+1.0);
		G::gaussbuild();
		printf("%.5lf\n",G::gauss(m1+m2+1));
	}
	return 0;
}

B. B君的回忆

取 \(mod\) 意义下一定存在循环节,于是直接打表找规律

得出如下规律

将 \(p\) 分解为 \(\prod\limits_{i=1}^{cnt}pri_i^{c_i}\) 的形式

于是他的循环节长度为 \(\prod\limits_{i=1}^{cnt}f(pri_i)\times pri_i^{c_i-1}\)

\(f(x)\) 表示 \(\mod x\) 意义下循环节的长度

对于每个 \(f(x)\) 可以直接用矩阵 \(bsgs\) 求

每个 \(g(n)\) 都可以变成 \(a^xc\) 的形式( \(a,c\) 均为矩阵 )

于是套 \(bsgs\) 的板子 \(a^x\equiv b(\mod p)\) 稍微变化一下就能求 \(a^xc\equiv b(\mod p)\) 了

最后把答案都乘起来,对于每一层都求一遍就行

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int T,a,b,n,k,mod;
int tmod[110];
map<int,int>AAA;
struct mat{
	int a[4][4];
	inline mat operator*(mat const &b)const{
		mat c;memset(c.a,0,sizeof(c.a));
		for(int i=1;i<=2;i++) for(int k=1;k<=2;k++) for(int j=1;j<=2;j++) (c.a[i][j]+=a[i][k]*b.a[k][j])%=mod;
		return c;
	}
	inline bool operator<(const mat &b)const{for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) if(a[i][j]!=b.a[i][j]) return a[i][j]<b.a[i][j];return false;}
	inline bool operator==(const mat &b)const{for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) if(a[i][j]!=b.a[i][j]) return false;return true;}
	inline bool empty(){for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) if(a[i][j]) return false;return true;}
	inline void print(){for(int i=1;i<=2;i++,puts("")) for(int j=1;j<=2;j++) printf("%lld ",a[i][j]);}
}A,B;
inline mat qpow(mat x,int k){
	mat res,base=x;for(int i=1;i<=2;i++) for(int j=1;j<=2;j++) res.a[i][j]=(i==j);
	while(k){if(k&1) res=res*base;base=base*base;k>>=1;}
	return res;
}
inline int g(int x){
	if(x==1) return b;if(x==0) return a;
	memset(B.a,0,sizeof(B.a));
	memset(A.a,0,sizeof(A.a));
	B.a[1][1]=b;B.a[2][1]=a;
	A.a[1][1]=3,A.a[1][2]=mod-1;
	A.a[2][1]=1,A.a[2][2]=0;
	A=qpow(A,x-1);B=A*B;
	return B.a[1][1];
}
namespace MODDDD{
	int prime[100],c[100],cnt,res;
	map<mat,int> mp;
	inline int bsgs(mat a,mat b,mat c,int p){
		if((qpow(a,p)*c)==b) return p;
		if((qpow(a,p-1)*c)==b) return p-1;
		if((qpow(a,p+1)*c)==b) return p+1;
		mp.clear();int t=sqrt(p)+1;mat w;memset(w.a,0,sizeof(w.a));for(int i=1;i<=2;i++) w.a[i][i]=1;
		for(int i=0;i<=t;i++,w=w*a) mp[w*b]=i;
		a=qpow(a,t);
		if(a.empty()) return (b.empty())?1:-1;
		memset(w.a,0,sizeof(w.a));for(int i=1;i<=2;i++) w.a[i][i]=1;
		for(int i=0,j;i<=t;i++,w=w*a){
			j=mp.find(w*c)==mp.end()?-1:mp[w*c];
			if(j>=0&&i*t-j>0) return i*t-j;
		}
		return -1;
	}
	inline int getP(int pri){
		mod=pri;
		memset(B.a,0,sizeof(B.a));
		memset(A.a,0,sizeof(A.a));
		B.a[1][1]=1;B.a[2][1]=0;
		A.a[1][1]=3,A.a[1][2]=mod-1;
		A.a[2][1]=1,A.a[2][2]=0;
		return bsgs(A,B,B,mod);
	}
	int gcd(int x,int y){return (!y)?x:gcd(y,x%y);}	
	inline int getmod(int p){
		if(AAA.find(p)!=AAA.end()) return AAA[p];
		int xxxx=p;
		cnt=0;res=1;
		for(int i=2;i*i<=p;i++) if(p%i==0){
			prime[++cnt]=i;c[cnt]=0;
			while(p%i==0) p/=i,c[cnt]++;
		}
		if(p>1) prime[++cnt]=p,c[cnt]=1;
		for(int i=1,gg,cc;i<=cnt;i++){
			cc=getP(prime[i]);
			cc=(cc==-1?prime[i]:cc);
			for(int j=1;j<c[i];j++) cc=cc*prime[i];
			gg=gcd(res,cc);
			res=res*cc/gg;
		}
		return AAA[xxxx]=res;
	}
}
int F(int n,int k){
	if(k==0) return n;
	mod=tmod[k];
	return F(g(n),k-1);
}
inline void solve(){
	a=read(),b=read(),n=read(),k=read(),mod=read();
	tmod[1]=mod;for(int i=2;i<=k;i++) tmod[i]=mod=MODDDD::getmod(mod);
	printf("%lld\n",F(n,k));
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	T=read();while(T--) solve();
	return 0;
}

C. 小 H 爱染色

要求 \(\sum\limits_{i=0}^{n-1}F(i)\times H(n-i)\)

球的编号从 \(0\) 到 \(n-1\)

\(F(x)\) 为给定不超过 \(m\) 次的多项式

\(H(i)\) 为给 \(i\) 个球染色其中第一个球必须染

朴素的式子为 \(H(i)=2\binom{i}{m-1}\binom{i}{m}+\binom{i}{m-1}^2\) 没啥拓展性

再看上面的式子 \(\sum\limits_{i=0}^{n-1}F(i)\times H(n-i)\)

可以对于每个 \(j\) 求出答案于是变成,为了方便把 \(n-1\) 变成 \(n\)

\(\sum\limits_{j=0}^mf_j\sum\limits_{i=0}^nH(n-i)i^j\)

考虑 \(i^j\) 的组合意义

\(i\) 个球染色一次染一个一共染 \(j\) 次

于是可以把两个式子化在一起,直接枚举两部分各染了几个球分别记录为 \(t,k\) ,这样就不需要枚举 \(i\) 了因为第 \(i\) 个球是后 \(k\) 个里的第一个所以一定被染了

后面的方案数为 \(\binom{k}{m}\binom{m}{2m-k}\)

一共染 \(k\) 个,第一次先挑 \(m\) 个染,第二次先把没染的染了再从剩下的挑

前面的相当于 \(t\) 个球染 \(j\) 次,所有的都被染了,二项式反演一下就行

方案数为 \(\sum\limits_{i=0}^t\binom{t}{i}(-1)^{i}(t-i)^j\)

然后就变成了 \(\sum\limits_{j=0}^{m}f_j\sum\limits_{t=0}^m\sum\limits_{k=m}^{2m}\binom{n}{t+k}\binom{k}{m}\binom{m}{2m-k}\sum\limits_{i=0}^t\binom{t}{i}(-1)^{i}(t-i)^j\)

\(\binom{n}{t+k}\) 注意到 \(H(i)\) 为给 \(i\) 个球染色其中第一个球必须染的方案数,你不需要知道到底时哪 \(i\) 个

然后你总共会染 \(t+k\) 个,所以直接 \(\binom{n}{t+k}\)

发现 \(j\) 只在最后有用于是直接挪过去

\(\sum\limits_{t=0}^m\sum\limits_{k=m}^{2m}\binom{n}{t+k}\binom{k}{m}\binom{m}{2m-k}\sum\limits_{i=0}^t\binom{t}{i}(-1)^{i}\sum\limits_{j=0}^m(t-i)^j\)

\(\sum\limits_{j=0}^m(t-i)^j\) 这个东西就相当与给定的多项式第 \(t-i\) 项

然后剩下的就能卷积了,先卷 \(f(t)=\sum\limits_{i=0}^t\binom{t}{i}(-1)^{i}F(t-i)\) 再卷 \(\sum\limits_{t=0}^m\sum\limits_{k=m}^{2m}\binom{n}{t+k}\binom{k}{m}\binom{m}{2m-k}f(t)\)

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define mod 998244353
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,ans,m3,m2;
int f[4194310],g[4194310];
int fac[3000010],inv[3000010],C[3000010];
inline int Binom(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
inline void md(int &x){x=(x>=mod)?x-mod:x;}
inline void mmd(int &x){x=(x>=mod)?x%mod:x;}
namespace POLY{
	int len,L,INV;
	int r[4194310],G[4194310];
	inline void pre(int lim){
		for(len=1,L=0;len<=lim;len<<=1,L++);
		for(rint i=0;i<len;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
		G[0]=1,G[1]=qpow(3,(mod-1)/len);for(rint i=2;i<=len;++i) mmd(G[i]=G[i-1]*G[1]);
	}
	inline void rev(){G[0]=1,G[1]=qpow(G[1],mod-2);for(rint i=2;i<=len;++i) mmd(G[i]=G[i-1]*G[1]);}
	inline void ntt(int a[]){
		for(rint i=0;i<len;++i) if(i<r[i]) a[i]^=a[r[i]]^=a[i]^=a[r[i]];
		for(rint d=1,t=len>>1;d<len;d<<=1,t>>=1) for(rint i=0;i<len;i+=(d<<1)) for(rint j=0;j<d;j++){
			int tmp;mmd(tmp=G[t*j]*a[i+j+d]);
			md(a[i+j+d]=a[i+j]-tmp+mod);
			md(a[i+j]=a[i+j]+tmp);
		}
	}
	inline void mul(){
		ntt(f);ntt(g);for(rint i=0;i<len;++i) mmd(f[i]=f[i]*g[i]);
		rev();ntt(f);INV=qpow(len,mod-2);
		for(rint i=0;i<len;++i) mmd(f[i]=f[i]*INV);
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	n=read(),m=read();m3=m*3;m2=m+m;
	for(rint i=0;i<=m;++i) f[i]=read();
	fac[0]=1;for(rint i=1;i<=m3;++i) mmd(fac[i]=fac[i-1]*i);inv[m3]=qpow(fac[m3],mod-2);
	inv[0]=1;for(rint i=m3-1;i;i--) mmd(inv[i]=inv[i+1]*(i+1));
	C[0]=1;for(rint i=1;i<=m3;++i) mmd(C[i]=C[i-1]*(n-i+1)%mod*inv[i]%mod*fac[i-1]);
	for(rint i=0;i<=m;++i) mmd(f[i]=f[i]*inv[i]);
	for(rint i=0,r=1;i<=m;i++,r=-r) md(g[i]=(r*inv[i]%mod+mod));
	POLY::pre(m2);POLY::mul();
	for(rint i=0;i<=m;++i) mmd(f[i]=f[i]*fac[i]);for(rint i=m+1;i<=m2;++i) f[i]=0;
	memset(g,0,sizeof(g));
	for(rint i=m;i<=m2;++i) mmd(g[i]=Binom(i,m)*Binom(m,m2-i));
	POLY::pre(m3);POLY::mul();
	for(rint i=m;i<=m3;++i) md(ans=(ans+f[i]*C[i]%mod));
	printf("%lld\n",ans);
	return 0;
}

标签:专项,ch,return,limits,int,sum,数学,测试,binom
来源: https://www.cnblogs.com/MaxQAQ/p/15773032.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有