zoukankan      html  css  js  c++  java
  • 2021.02.28模拟赛总结

    看A,B,C看上去都不是我擅长的题目。
    C感觉要会猜结论,A,B都是计数。
    冷静一下,看A发现可以枚举每个操作的摆放位置,求出对答案的贡献。
    求贡献可以用一个被化成多项式的dp解决。
    然后直接做只能(O(n^2))
    再想了很久才发现在多项式内相同的项可以在一起维护,这样子可以用分治fft在(O(nlog_2^2n))时间内解决。
    然后看B,只会暴力。
    然后还有40分(其实是20分)的暴力dp+莫反(不用fwt)
    由于时间不多了,所以就只写了暴力dp+莫反。
    看C好像只会暴力。
    然后最后测评时发现自己的暴力dp+莫反re了前两个点。
    这是因为读错部分分。
    总结:
    发挥一般,有失误但是不大。
    B没有什么时间思考,而且读错部分分是一个失误。
    由于读错n,(max{a_i})的失误,导致没有想出正解。
    C这种图论题本来自己就不擅长。
    而且NOI/省选出这种题肯定没什么人得高分。
    所以自己在这题上没有出现失误。
    题解:
    A:
    考虑枚举每一个数放的位置(i),计算它的贡献。
    显然它的贡献就是它后面的乘法操作的个数(*frac{i!}{(n-i)!})
    考虑dp求解。设(f_{i,j})表示放置前(i)个数,有(j)个数对答案产生贡献的方案。
    (f_{i,j}=p_if_{i-1,j}+(1-p_i)b_if_{i-1,j-1})
    (F_i=sum x^jf_{i,j})
    (F_i=((1-p_i)b_ix+p_i)F_{i-1})
    (sum F_{n-1}[x^j]frac{j!}{(n-j)!})就是答案。
    发现(F_i)表示(prod ((1-p_i)b_ix+p_i))除以一项,所以把这些数都乘起来然后每次除就有(50)分了。
    注意到对于每个(x^j),对答案的贡献都是相同的。
    可以用分治fft处理出多项式除以每个单项式的值然后求出答案。

    #include<bits/stdc++.h>
    using namespace std;
    #define mo 998244353
    #define N 500010
    #define ll unsigned long long
    #define int long long
    #define pl vector<int>
    int qp(int x,int y){
    	int r=1;
    	for(;y;y>>=1,x=1ll*x*x%mo)
    		if(y&1)r=1ll*r*x%mo;
    	return r;
    }
    int n,m,rev[N],v,le,w[N];
    void deb(pl x){
    	for(int i:x)cout<<i<<' ';
    	puts("");
    }
    void init(int n){
    	v=1;
    	le=0;
    	while(v<n)le++,v*=2;
    	for(signed i=0;i<v;i++)
    		rev[i]=(rev[i>>1]>>1)|((i&1)<<(le-1));
    	int g=qp(3,(mo-1)/v);
    	w[v/2]=1;
    	for(int i=v/2+1;i<v;i++)
    		w[i]=1ull*w[i-1]*g%mo;
    	for(signed i=v/2-1;~i;i--)
    		w[i]=w[i*2];
    }
    void fft(int v,pl &a,int t){
    	static unsigned long long b[N];
    	int s=le-__builtin_ctz(v);
       	for(int i=0;i<v;i++)
       		b[rev[i]>>s]=a[i];
    	int c=0;
    	w[0]=1;
        for(signed i=1;i<v;i*=2,c++)
        	for(signed r=i*2,j=0;j<v;j+=r)
                for(signed k=0;k<i;k++){
                   	int tx=b[j+i+k]*w[k+i]%mo;
                	b[j+i+k]=b[j+k]+mo-tx;
                	b[j+k]+=tx;
                }
        for(int i=0;i<v;i++)
        	a[i]=b[i]%mo;
        if(t==0)return;
        int iv=qp(v,mo-2);
        for(signed i=0;i<v;i++)
        	a[i]=1ull*a[i]*iv%mo;
        a.resize(v);
        reverse(a.begin()+1,a.end());
    }
    pl operator *(pl x,pl y){
    	int s=x.size()+y.size()-1;
    	if(x.size()<=30||y.size()<=30){
    		pl r;
    		r.resize(s);
    		for(int i=0;i<x.size();i++)
    			for(int j=0;j<y.size();j++)
    				r[i+j]=(r[i+j]+x[i]*y[j])%mo;
    		return r;
    	}
    	init(s);
    	x.resize(v);
    	y.resize(v);
    	fft(v,x,0);
    	fft(v,y,0);
    	for(int i=0;i<v;i++)
    		x[i]=x[i]*y[i]%mo;
    	fft(v,x,1);
    	x.resize(s);
    	return x;
    }
    void ad(pl &x,pl y,int l){
    	x.resize(max((int)x.size(),(int)y.size()+l));
    	for(int i=0;i<y.size();i++)
    		x[i+l]=(x[i+l]+y[i])%mo;
    }
    pl operator +(pl x,pl y){
    	ad(x,y,0);
    	return x;
    }
    int p[N],a[N],b[N],jc[N],ij[N];
    pl c[N],d[N],s[N];
    void fz(int o,int l,int r){
    	if(l==r){
    		d[o].resize(2);
    		d[o][0]=1;
    		d[o][1]=b[l];
    		pl va;
    		va.resize(1);
    		va[0]=a[l];
    		s[o]=va;
    		return;
    	}
    	int md=(l+r)/2;
    	fz(o*2,l,md);
    	fz(o*2+1,md+1,r);
    	d[o]=d[o*2]*d[o*2+1];
    	s[o]=s[o*2]*d[o*2+1]+s[o*2+1]*d[o*2];
    }
    signed main(){
    	freopen("operation.in","r",stdin);
    	freopen("operation.out","w",stdout);
    	scanf("%lld",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%lld%lld%lld",&p[i],&a[i],&b[i]);
    		int c=a[i],d=b[i];
    		a[i]=p[i]*c%mo;
    		b[i]=(b[i]+p[i]-p[i]*b[i]%mo+mo)%mo;
    	}
    	jc[0]=1;
    	for(int i=1;i<N;i++)
    		jc[i]=jc[i-1]*i%mo;
    	ij[N-1]=qp(jc[N-1],mo-2);
    	for(int i=N-1;i;i--)
    		ij[i-1]=ij[i]*i%mo;
    	int ans=0;
    	fz(1,1,n);
    	for(int i=0;i<n;i++)
    		ans=(ans+jc[i]*jc[n-i-1]%mo*s[1][i]%mo)%mo;
    	printf("%lld",ans*ij[n]%mo);
    }
    

    B:
    考虑莫反,我们要计算(sum mu(i)*)提取被(i)整除的数后,(b_1...b_k)xor起来(=s)的个数。
    (c_i)表示(i)出现的次数
    发现(max(a_i)=v)比较小,但是(n)比较大,所以从(c)的方面进行考虑。
    对于每个数(x)把倍数对应的(c)提取出来。
    当提取出来的元素较多((geq sqrt{max(a_i)}))时显然可以(fwt)计算。
    当提取出来的元素较少时,可以考虑折半。
    预处理出前(2)个数,后(2)个数的方案数,然后枚举左边的取值,右边的取值就是(s^)左边的取值。
    但是我们算出的答案可能下标会重复 ,需要容斥。
    考虑一张点数为(4)的图,如果下标重复则把对应的下标连边。
    然后发现每个连通块一定要是相同的。
    然后可以使用前面的方法进行计算。
    时间复杂度(O(vsqrt{v}log_2v))

  • 相关阅读:
    c#时间函数
    .NET中的lock(C#版本)
    关于OpenSmtp邮件标题过长,附件名,用户名出现乱码问题的终及解决Dll文件
    Windbg 用法
    使用OpenXML将数据导入到Excel模板中
    Compiere源码workspace的两个配置文件内容
    我学MEF系列(8):MEF+Unity实现可扩展拦截器
    基于插件架构的简单的Winform框架(上)
    我学Flash/Flex(2):AS3读取XML文件内容
    我学Flash/Flex(1):Action Script3.0基础知识
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14459172.html
Copyright © 2011-2022 走看看