6812. 【2020.10.05提高组模拟】战争

题目

有若干个国家,第 i i i个国家有 a i a_i ai个部落。

国家之间会随机地发生战争,对于两个国家 A A A B B B(分别表示其部落的数目),发生战争后:

p p p的概率变成国家 A + 1 A+1 A+1 B − 1 B-1 B1个国家 1 1 1

p p p的概率变成国家 B + 1 B+1 B+1 A − 1 A-1 A1个国家 1 1 1

1 − 2 p 1-2p 12p的概率变成 A + B A+B A+B个国家 1 1 1

问大一统的期望战争次数。

n ≤ 4 ∗ 1 0 7 n\le 4*10^7 n4107,输入由奇怪的方式给出。

模质数。


神仙题。

题解是构造了一个与当前状态有关的函数,某个状态和终止状态的函数值之差和这个状态中间是转移的没有关系。可以比作势能。

这里构造的是: f ( { a i } ) = ∑ ( p − a i − p − 1 ) f(\{a_i\})=\sum(p^{-a_i}-p^{-1}) f({ ai})=(paip1)。在这个函数下,终止状态为最大值。

不妨设 a 1 a_1 a1 a 2 a_2 a2间发生战争,那么函数值的变化为: Δ = p ( p − a 1 − 1 − p − 1 ) + p ( p − a 2 − 1 − p − 1 ) − ( p − a 1 − p − 1 ) − ( p − a 2 − p − 1 ) = 2 p − 1 − 2 \Delta =p(p^{-a_1-1}-p^{-1})+p(p^{-a_2-1}-p^{-1})-(p^{-a_1}-p^{-1})-(p^{-a_2}-p^{-1})=2p^{-1}-2 Δ=p(pa11p1)+p(pa21p1)(pa1p1)(pa2p1)=2p12

发现它是一个定值。

于是答案为 f ( 终 止 ) − f ( 当 前 ) Δ \frac{f(终止)-f(当前)}{\Delta} Δf()f()


卡了半天的常才过去。。。

#pragma G++ optimize(2)
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define mo 1000000007
#define ll unsigned long long
ll qpow(ll x,ll y=mo-2){
    
    
	y%=mo-1;
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
int n,s,t,p;
ll invp,ans,sum;
int sq;
ll pw0[1<<17|5],pw1[1<<17|5];
void init(ll x){
    
    
	sq=1<<17;
	pw0[0]=1;
	for (int i=1;i<sq;++i)
		pw0[i]=pw0[i-1]*x%mo;
	x=qpow(x,sq);
	pw1[0]=1;
	for (int i=1;i<sq;++i)
		pw1[i]=pw1[i-1]*x%mo;
}
ll input(){
    
    
	char ch=getchar();
	while (ch<'0' || ch>'9')
		ch=getchar();
	ll x=0;
	do{
    
    
		x=x*10+ch-'0';
		ch=getchar();
	}
	while ('0'<=ch && ch<='9');
	return x;
}
int main(){
    
    
//	freopen("in.txt","r",stdin);
	freopen("warfare.in","r",stdin);
	freopen("warfare.out","w",stdout);
	int T;
	scanf("%d%d%d%d",&T,&n,&s,&t);
	p=(ll)s*qpow(t)%mo;
	invp=qpow(p);
	init(invp);
	if (T==0){
    
    
		for (int i=1;i<=n;++i){
    
    
			ll x;
			scanf("%llu",&x);
			ll t=x%(mo-1);
			sum+=t;
			(ans+=pw1[t/sq]*pw0[t%sq]-invp+mo)%=mo;
		}
	}
	else{
    
    
		int m;
		ll x,y,z,b1,b2;
		scanf("%d%llu%llu%llu%llu%llu",&m,&x,&y,&z,&b1,&b2);
		register int j=1;
		while (m--){
    
    
			int q=input();
			ll l=input(),r=input();
			for (;j<=q;++j){
    
    
				ll t=(b1%(r-l+1)+l)%(mo-1);
				sum+=t;
				(ans+=pw1[t>>17]*pw0[t&(1<<17)-1]-invp+mo)%=mo;
				t=x*b2+y*b1+z;
				b1=b2,b2=t;
			}
		}
	}
	ll mx=(qpow(invp,sum)-invp+mo)%mo;
	printf("%llu\n",(mx-ans+mo)*qpow((2*invp-2+mo)%mo)%mo);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/A1847225889/article/details/108944108