Codeforces 806F:Test Data Generation(组合数学)

传送门

题解:
相当于是要求:

u i = 1 n 2 u [ i ] j = 1 n 1 [ j ] ( i 1 j ) \sum_{u}\sum_{i=1}^{\lfloor\frac{n}{2^u}\rfloor}[i为奇数] \sum_{j=1}^{n-1}[j为偶数] \binom{i-1}{j}

然后注意这个 j j 比较小,我们可以对组合数分治递归为左边选多少个,右边选多少个,然后卷积起来。 这样而且刚好能把所有 n 2 u \frac{n}{2^u} 的情况考虑到。时间复杂度 O ( n log n log A ) O(n \log n \log A)

#include <bits/stdc++.h>
using namespace std;

int mod;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}

namespace FFT {
    #define double long double
	const int N=1e6+50;
	const double PI2=acos(-1.0)*2.0;
	int pos[N],k;
	struct CP {
		double r,i;
		CP() {}
		CP(double r,double i) : r(r),i(i) {}
		friend inline CP operator *(const CP &a,const CP &b) {return CP(a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r);}
		friend inline CP operator +(const CP &a,const CP &b) {return CP(a.r+b.r,a.i+b.i);}
		friend inline CP operator -(const CP &a,const CP &b) {return CP(a.r-b.r,a.i-b.i);} 
	} A[N],B[N],w[N];
	inline void dft(CP *a) {
		for(int i=1;i<k;i++)
			if(pos[i]>i) swap(a[pos[i]],a[i]);
		for(int bl=1;bl<k;bl<<=1) {
			int tl=bl<<1; CP wn=CP(cos(PI2/tl),sin(PI2/tl));
			w[0]=CP(1,0); for(int i=1;i<bl;i++) w[i]=w[i-1]*wn;
			for(int bg=0;bg<k;bg+=tl)
				for(int j=0;j<bl;j++) {
					CP &t1=a[bg+j], &t2=a[bg+j+bl], t=t2*w[j];
					t2=t1-t; t1=t1+t;
				}
		}
	}
	inline void init(int n) {
		for(k=1;k<=n;k<<=1);
		for(int i=1;i<k;i++)
			pos[i]=(i&1) ? ((pos[i>>1]>>1)^(k>>1)) : (pos[i>>1]>>1);
		for(int i=0;i<k;i++) A[i]=B[i]=CP(0,0);
	}
	inline void func() {
		dft(A); dft(B);
		for(int i=0;i<k;i++) A[i]=A[i]*B[i];
		dft(A); reverse(A+1,A+k);
		for(int i=0;i<k;i++) A[i].r/=k;
	}
    #undef double
}

int n,A,ans;
struct poly {
	vector <int> a;
	poly(int d=0,int t=0) {a.resize(d+1); a[d]=t;}
	inline int deg() const {return a.size()-1;}
	inline int& operator[](const int &i) {return a[i];}
	inline const int& operator[](const int &i) const {return a[i];} 
	friend inline poly operator +(const poly &a,const poly &b) {
		poly c(max(a.deg(),b.deg()),0);
		for(int i=0;i<=a.deg();i++) c[i]=add(c[i],a[i]);
		for(int i=0;i<=b.deg();i++) c[i]=add(c[i],b[i]);
		return c;
	}
	friend inline poly operator *(const poly &a,const poly &b) {
		poly c(a.deg()+b.deg()); 
        if(a.deg()>20 && b.deg()>20) {
            FFT::init(c.deg());
            for(int i=0;i<=a.deg();i++) FFT::A[i].r=a[i];
            for(int i=0;i<=b.deg();i++) FFT::B[i].r=b[i];
            FFT::func();
            for(int i=0;i<=c.deg();i++)  {
                c[i]=((long long)(FFT::A[i].r+0.1))%mod;
                assert(c[i]>=0 && c[i]<mod);
            }
        } else {
            for(int i=0;i<=b.deg();i++)
                for(int j=0;j<=a.deg();j++)
                    c[i+j]=add(c[i+j],mul(a[j],b[i]));
        }
		if(c.deg()>=n) c.a.resize(n); return c;
	}
	inline int get_sum() {
		int t=0;
		for(int i=0;i<n && i<=deg();i+=2) t=add(t,a[i]);
		return t;
	}
};
struct mat {
	poly a[2][2];
	mat(int t) {
		if(t==1) {
			a[0][0]=poly(0,1);
			a[1][1]=poly(1,1);
			a[1][1].a[0]=1;
		}
	}
	friend inline mat operator *(const mat &a,const mat &b) {
		mat c(0);
		for(int i=0;i<=1;++i)
			for(int j=0;j<=1;++j)
				for(int k=0;k<=1;k++)
					c.a[i][j^k]=c.a[i][j^k]+a.a[1][j]*b.a[i][k];
		for(int k=0;k<=1;k++)
			c.a[0][k]=c.a[0][k]+a.a[0][k];
		return c;
	}
};
inline mat solve(int T,int flag) {
	if(T==1) {
		if(flag) ans=add(ans,1);
		return mat(1);
	}
	if(T&1) {
		mat tp=solve(T-1,0)*mat(1);
		if(flag) ans=add(ans,tp.a[0][0].get_sum());
        return tp;
	} else {
		mat tp=solve(T/2,1);
		tp=tp*tp;
		if(flag) ans=add(ans,tp.a[0][0].get_sum());
        return tp;
	}
}
int main() {
	cin>>n>>A>>mod;
	mat a(1);
	solve(A,0);
	cout<<ans<<'\n';
}
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/84655394