CF773F Test Data Generation
没能自己推出来/kk
显然,题目的限制条件就是:
-
选择奇数个数,且总数 \(\le max_n\)
-
\(a_n\bmod 2=0,\dfrac{a_n}{g}\bmod 2=1\)
直接枚举 \(g\) 的最高的 \(2\) 的次幂可以将限制二转化为:在 \([1,\dfrac{max_a}{2^k}]\) 中选数,最大的数是奇数。
枚举最大数,枚举选的数的个数可以得到一个 \(O(na\log a)\) 的暴力(这个 \(\log\) 的来源是:每次传 a=maxa>>i
进去)
for(int i=1;i<=a;i+=2)
for(int j=1;j<=n;j+=2)
ans+=C[i-1][j-1];
推到这里就我推不动了/kk,一直考虑怎么算这个式子发现完全不会。。。然后只好去看题解/kk
用生成函数 \(F(a,p)=\sum f(i,a,p)z^i\) , \(f(i,a,p)\)表示在 \([1,a]\) 中选数,最大数奇偶性为 \(p\) 选了 \(i\) 个的方案数,并且规定 f(0,x,y)=0
,即不包括选 \(0\) 个数的情况
然后就是两个很牛逼的转移
怎么说呢?看到这个转移一下子就能懂,自己就是写不出来/kk
第一行:在 \([1,2a]\) 中选数,相当于只选 \(\le a\) 的,再加上,选一部分 \(\le a\) 的并且加 \(a\) ,就能出现 \(>a\) 的数了。
(如果生成函数看不习惯可以写成卷积的形式,可能更好理解)
具体来说,前 \(i\) 个数 \(\le a\) 并且随便选,后 \(n-i\) 个数 \(\le a\) 然后加 \(a\) ,同时要保证最大数的奇偶性,就有了第一行转移。妙啊!
第二行:分选 \(a+1\) 与不选 \(a+1\) 来讨论。不选就是 \(F(a,p)\) ,选 \(a+1\) 那么 \(\le a\) 的数就随便选了。
直接倍增FFT求解。但是记住 \(g\) 中 \(2\) 的最高次幂不能是 \(0\) ,所以读进来的 \(a\) 要除以 \(2\) 。我tm写着写着忘掉了,白调了一个小时/kk
另外,这题并不用MTT,\(1e5\) 以内卷起来不会有精度问题,最大卷起来 \(1e5*1e5*3e4=3e14\) ,而且远达不到,炸不掉 double
的精度,好调好写跑得快。
虽然这题要对 \(\log a\) 种 \(a\) 求值,但是显然,每倍增一位就统计一次答案可以随手消掉这个 \(\log a\) ,总复杂度还是倍增FFT的复杂度 \(O(n\log n\log a)\)。
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define sz(v) (int)v.size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?x:-x;
}
const int N=30005;
const int M=N<<2;
int n,a,mod,f[2][M],ans;
int fmod(int x){return x-=mod,x+=x>>31&mod,x;}
namespace poly{
const db PI=acos(-1);
struct cp{
db x,y;
cp(){x=y=0;}
cp(db x_,db y_){x=x_,y=y_;}
cp operator + (const cp&t)const{return cp(x+t.x,y+t.y);}
cp operator - (const cp&t)const{return cp(x-t.x,y-t.y);}
cp operator * (const cp&t)const{return cp(x*t.x-y*t.y,x*t.y+y*t.x);}
}w[M];
int rev[M],lim,lg;
void init(const int&n){
for(lg=0,lim=1;lim<n;++lg,lim<<=1);
for(int i=0;i<lim;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),w[i]=cp(cos(2*PI*i/lim),sin(2*PI*i/lim));
}
void FFT(cp*a,int op){
for(int i=0;i<lim;++i)if(i>rev[i])swap(a[i],a[rev[i]]);
for(int i=1,t=lim>>1;i<lim;i<<=1,t>>=1){
for(int j=0;j<lim;j+=i<<1){
for(int k=0;k<i;++k){
const cp X=a[j+k],Y=w[k*t]*a[i+j+k];
a[j+k]=X+Y,a[i+j+k]=X-Y;
}
}
}
if(op)return;
for(int i=0;i<lim;++i)a[i].x/=lim;
}
void mul(int*f,int*g,int*ans){
static cp A[M],B[M];
for(int i=0;i<lim;++i)A[i]=cp(f[i],0),B[i]=cp(g[i],0);
FFT(A,1),FFT(B,1);
for(int i=0;i<lim;++i)A[i]=A[i]*B[i],w[i].y*=-1;
FFT(A,0);
for(int i=0;i<lim;++i)ans[i]=LL(A[i].x+0.5)%mod;
for(int i=0;i<lim;++i)w[i].y*=-1;
}
#define clr(a,n) memset(a,0,sizeof(int)*(n))
void shift(const int&n,const int&a){
static int g[M],h[M],q[M];
clr(g,lim),clr(h,lim),clr(q,lim),g[0]=1;
for(int i=1;i<=n;++i)g[i]=fmod(f[0][i]+f[1][i]);
mul(g,f[a&1],h),mul(g,f[(a&1)^1],q);
for(int i=1;i<=n;++i)f[0][i]=fmod(f[0][i]+h[i]),f[1][i]=fmod(f[1][i]+q[i]);
}
void setbit(const int&n,const int&a){
static int g[N];g[0]=1;
for(int i=1;i<=n;++i)g[i]=fmod(f[0][i]+f[1][i]),f[1][i]=fmod(f[1][i]+g[i-1]);
}
}
signed main(){
n=read(),a=read()>>1,mod=read();
if(!a)return puts("0"),0;
f[1][1]=ans=1,poly::init(n<<1);
for(int i=log2(a)-1,len=1;i>=0;--i){
poly::shift(n,len),len<<=1;
if(a>>i&1)poly::setbit(n,len),++len;
for(int j=1;j<=n;j+=2)ans=fmod(ans+f[1][j]);
}
printf("%d\n",ans);
return 0;
}