dice程序解析

zby大佬的博客
密码::???为啥去那么怪的密码
∑i=1np2i(2vi∑S,i∉S|S+1|!∏x∈Spx+∑x≠ipxvx∑S,i,x∉S|S+2|!∏y∈Spy)

通过一系列的变化及

变化1

Ans=∑S|S|!∑i∈Sp2i∏x∈S,x≠ipx(2vi+∑x∈S,x≠ivx)
通过(暴力思想枚举全排列)得出ans表达式

变化2

∑i=1np2i∑S,i∉S|S+1|!(2vi∏x∈Spx+∏x∈Spx∑x∈Svx)

变化3

∑i=1np2i(2vi∑S,i∉S|S+1|!∏x∈Spx+∑x≠ipxvx∑S,i,x∉S|S+2|!∏y∈Spy)

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define MOD 998244353
using namespace std;
int n,m,f[100010],fac[100010],h[10010],a[100010],b[10010],dp[100010];
const unsigned long long limi=1e19 ;
void inc(int &x,int y) {
	x+=y;
	if (x>=MOD) x-=MOD;
}
void inv(int *a,int &b) {
	REP(i,1,n-1) inc(a[i],MOD-1ll*b*a[i-1]%MOD);
}
void read(int &x) {
	x=0;
	int f=1;
	char c=getchar();
	for(; !isdigit(c); c=getchar()) if (c=='-') f=-f;
	for(; isdigit(c); c=getchar()) x=x*10+c-'0';
	x*=f;
}
int main() {
	read(n);
	REP(i,1,n) read(a[i]);
	REP(i,1,n) read(b[i]);
	fac[0]=fac[1]=1;
	dp[0]=1;
	REP(i,2,n) fac[i]=1ll*fac[i-1]*i%MOD;
	REP(i,1,n) for(int j=n; j; --j)
		inc(dp[j],1ll*dp[j-1]*b[i]%MOD);
	int total=0;
	REP(k,1,n) {
		memcpy(f,dp,sizeof(f)); 
		inv(f,b[k]);
		unsigned long long s=0,S=0;
		REP(i,0,n-1) {
			s+=1ull*f[i]*fac[i+1];
			if (s>=limi) s%=MOD;
		}
		s%=MOD;
		s=2*1ull*a[k]*s%MOD;
		REP(x,1,n) {
			if (x==k) continue;
			memcpy(h,f,sizeof(h));
			inv(h,b[x]);
			S=0;
			REP(i,0,n-2) {
				S+=1ull*h[i]*fac[i+2];
				if (S>=limi) S%=MOD;
			}
			S%=MOD;
			S=1ull*a[x]*b[x]%MOD*S%MOD;
			s+=S;
		}
		s%=MOD;
		total=(total+s*b[k]%MOD*b[k])%MOD; 
	}
	cout<<total<<endl;
}

有点丑,astyle名副其实。。。

···
REP(i,2,n) fac[i]=1ll*fac[i-1]*i%MOD;
·····
这一段
是为了求|S+1|!与|S+2|!的阶乘, fac正常o(n);

其实吧
REP(i,1,n) for(int j=n; j; --j)
		inc(dp[j],1ll*dp[j-1]*b[i]%MOD);

这一段是为了求出各个集合的概率,即求出选出其中i个的概率和

		s=2*1ull*a[k]*s%MOD;

这一段是求出 2vi*s这一段

REP(i,0,n-1) {
			s+=1ull*f[i]*fac[i+1];
			if (s>=limi) s%=MOD;
		}

这一段是为了求出∑S,i∉S|S+1|!∏x∈Spx

	inv(f,b[k]);

inv是求背包。。背包要退影响。。。所以要inv (f,b[k]);
所以总结下
inv是我最不懂的地方

memcpy(f,dp,sizeof(f)); 
		inv(f,b[k]);
		unsigned long long s=0,S=0;
		REP(i,0,n-1) {
			s+=1ull*f[i]*fac[i+1];
			if (s>=limi) s%=MOD;
		}
		s%=MOD;
		s=2*1ull*a[k]*s%MOD;

加个部分总结
这里是求 2vi∑S,i∉S|S+1|!∏x∈Spx 即括号内前半部分。。。无奈啊

	REP(x,1,n) {
			if (x==k) continue;
			memcpy(h,f,sizeof(h));
			inv(h,b[x]);
			S=0;
			REP(i,0,n-2) {
				S+=1ull*h[i]*fac[i+2];
				if (S>=limi) S%=MOD;
			}
			S%=MOD;
			S=1ull*a[x]*b[x]%MOD*S%MOD;
			s+=S;
		}

这里求的就是∑x≠ipxvx∑S,i,x∉S|S+2|!∏y∈Spy,括号里的后半段。。。

精细点解析

S+=1ull*h[i]*fac[i+2];
				if (S>=limi) S%=MOD;

这里求的是嗯嗯嗯∑x≠ipxvx∑S,i,x∉S|S+2|!∏这一段

后面的
循环外的(大循环内) 是为了把S乘上 这个∏y∈Spy

	S%=MOD;
			S=1ull*a[x]*b[x]%MOD*S%MOD;
			s+=S;

········
total=(total+sb[k]%MODb[k])%MOD;
·······
这个最后的求的是∑i=1np2i就是大括号外的那个数

最后得到total这个答案

数学代数题加公示变换加背包优化加编程思想加期望加逆元

这题目也是,,,,绝了。。。

现场怒打6行代码然后爆零。。。。

posted @ 2018-11-01 21:46  keydu  阅读(286)  评论(0)    收藏  举报