博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

正睿 青岛集训 Day4 Test


2019.3.5 青岛普转肯模拟赛day1暨徐源粉丝线下见面会

期望得分:70+20+40
实际得分:30+20+20

比赛链接

A.智慧树tree(树形DP NTT Bluestein)

题目链接

根据群里\(dalao\)的聊天记录,瞎猜理解了一波,重新理解了一遍DFT和NTT...会记在下面(\(dalao\)就忽略吧/kel)(我当时是学了些啥啊/kk)。


首先\(70\)分是直接用\(NTT\)优化背包(\(dp_i=\left(\prod_{v\in son_i}dp_v+1\right)\cdot x^{a_i}\))。就是每次转成点值,对应相乘,再转回去。复杂度是\(O(nm\log m)\)
蒟蒻表示虽然知道能这么做,但是不明白为什么做模\(m\)的循环卷积,这样还是对的/kk。重学了一下,因为我们代的是\(m\)次单位根,如果单位根的次数\(\geq m\),就又回去了,所以点值乘的时候就是对\(m\)取模的。

满分做法当然是,DP的过程中不转回系数表示,直接用点值表示做。统计答案时把点值累加,最后\(IDFT\)回去。
转移是\(dp_i(\omega_m^k)=\left(\prod_{v\in son_i}dp_v(\omega_m^k)+1\right)(\omega_m^k)^{a_i}\),那个\(+1\)是个常数(虽然是在系数表示下的\(+1\)),所以直接在点值处\(+1\)就可以了。
最初的正变换是\(n\)次单点的\(DFT\),直接每次代进\(m\)个单位根\(O(m)\)转成点值表示就可以了(\(A_i(\omega^k)=(\omega^k)^{a_i}\)),复杂度是\(O(nm)\)的。
注意到\(m\)不是\(2\)的次幂,而朴素\(NTT\)必须将多项式长度\(m\)补成\(2^k\),但是这样代的单位根就不是\(m\)次单位根了。也就是多项式长度必须是\(m\)
任意长度的\(DFT\)需要用到\(Bluestein's\ Algorithm\),下面写。

补充一点...当时学\(NTT\)没注意(或者忘掉)的东西。。
\(n=2^k\),那么取素数\(p=r\cdot2^k+1\)(满足这样形式的素数叫费马素数,朴素\(NTT\)必须是这样的模数,因为要存在任意\(2^i\ (i\leq k)\)的单位根),那么\(p\)存在\(n\)次单位根,且\(\omega_n=g^{\frac{p-1}{n}}\)
注意到这题模数\(p=950009857\)存在原根,且\(m=2^k,49152,57984\)都是\(p-1\)的约数,所以存在对应的\(m\)次单位根。

然而后几个点的\(m\neq2^k\),不能直接\(NTT\)(上面提到了),需要\(Bluestein\)。但是各位\(dalao\)说可以快速插值或者多点求值。。
学了下(也没学,就是看了下是干嘛的),大概就是,用点值DP完之后,我们可以得到\(m\)个点值,快速插值就可以得到原多项式的系数表示了。
注意到\(IDFT\)实际就是,将\(m\)次单位根的逆元代入点值出来的多项式,以得到原多项式的系数表示(\(c_k=\frac1m\sum\limits_{i=0}^{m-1}A(\omega_m^i)(\omega_m^{-i})^k\))。
所以也可以把点值的逆元代进去,多点求值就可以了。。
然而快速插值和多点求值都巨难写,而且常数大的恐怖吧。。(这辈子是不会写的.jpg)

正变换是\(O(nm)\)的,中间过程只有点值相乘也是\(O(nm)\)的,最后每个点用\(Bluestein\) \(IDFT\)回去是\(O(m\log m)\)的。


然后,记一下\(Bluestein's\ Algorithm\),用以解决任意长度\(DFT\)更多相关题目戳这
考虑\(DFT\)的形式:

\[\begin{aligned}y_k&=\sum_{i=0}^{n-1}a_i\omega_n^{ki}\\&=\sum_{i=0}^{n-1}a_i\omega_{2n}^{k^2+i^2-(k-i)^2}\\&=\omega_{2n}^{k^2}\sum_{i=0}^{n-1}a_i\omega_{2n}^{i^2}\omega_{2n}^{-(k-i)^2}\end{aligned} \]

注意到\(\sum\)是个卷积,可以用\(FFT/NTT\)计算。所以\(Bluestein\)的复杂度是\(O(n\log n)\)的。
具体:\(k-i\)可能是负的,所以对后一项右移\(n\)位,令\(f_i=a_i\omega_{2n}^{i^2},\ g_i=\omega_{2n}^{-(i-n)^2}\),那么\(y_k=\omega_{2n}^{k^2}\sum_{i}f_ig_{n+k-i}=\omega_{2n}^{k^2}(f\times g)_{n+k}\)

\(IDFT\)同理,可以直接令\(\omega_{2n}=\omega_{2n}^{-1}\),代到\(DFT\)的式子里,也可以一样的推一下:

\[\begin{aligned}c_k&=\frac{1}{n}\sum_{i=0}^{n-1}a_i\omega_n^{-ki}\\&=\frac{1}{n}\sum_{i=0}^{n-1}a_i\omega_{2n}^{k^2+i^2-(k+i)^2}\\&=\frac{1}{n}\omega_{2n}^{k^2}\sum_{i=0}^{n-1}a_i\omega_{2n}^{i^2}\omega_{2n}^{-(k+i)^2}\end{aligned} \]

\(f_i=a_i\omega_{2n}^{i^2},\ g_i=\omega_{2n}^{-(2n-1-i)^2}\),那么\(c_k=\frac{1}{n}\omega_{2n}^{k^2}\sum_if_ig_{2n-1-k-i}=\omega_{2n}^{k^2}(f\times g)_{2n-1-k}\)

上面是一般的做法(其实就是个\(trick\)),但是\(dls\)指出有更好一些的做法:
像这样写成平方需要\(\omega_{2n}\)(有些题可能不存在\(2n\)次单位根),就可以用:\(ij=\binom{i+j}{2}-\binom i2-\binom j2\)来替换:\(y_k=\omega_n^{-\binom k2}\sum_{i=0}^{n-1}a_i\omega_n^{-\binom i2}\omega_n^{\binom{i+j}{2}}\)

随便扯一句废话:\(m\)必须要有单位根才能做(直接\(FFT\)做DP 精度会爆炸)


最后,还有个问题是卡内存。
\(DFS\)的时候先\(DFS\)重儿子,然后父节点可以直接继承重儿子的DP数组,再\(DFS\)轻儿子。这样我们只需要记录当前\(O(轻链个数)\)\(=O(\log n)\)个DP数组。

关于类似的卡内存,有一道扩展题:
给定一棵\(n\)个点的树,每个点有一个重量和价值,你要选一个独立集,对于每个重量\(1,2,...,m\),求出其最大价值和。要求复杂度\(O(n^2m)\)
先DFS轻儿子子树,再考虑父节点,再考虑重儿子...状压现在有用的点的状态...(没听懂.jpg,望dalao解答)
做到了是这道题


//8523ms	6080kb
#include <cstdio>
#include <cctype>
#include <algorithm>
#define G 7
#define invG 135715694
#define mod 950009857
#define Mod(x) x>=mod&&(x-=mod)
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
#define gc() getchar()
#define MAXIN 200000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=8005,M=58000,M2=(1<<18)+1/*3m*/,S=30;

int n,m,A[N],W[M<<1],Enum,H[N],nxt[N<<1],to[N<<1],sz[N],son[N],top,sk[S],id[N],f[S][M],g[M2],h[M2],rev[M2],lim;
LL Ans[M];
bool vis[N];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now;
}
inline void AE(int u,int v)
{
	to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
	to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
inline int FP(int x,int k)
{
	int t=1;
	for(; k; k>>=1,x=1ll*x*x%mod)
		if(k&1) t=1ll*t*x%mod;
	return t;
}
void NTT(int *a,int lim,int opt)
{
	for(int i=1; i<lim; ++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);
	for(int i=2; i<=lim; i<<=1)
	{
		int mid=i>>1,Wn=FP(~opt?G:invG,(mod-1)/i);
		for(int j=0; j<lim; j+=i)
			for(int k=j,w=1,t; k<j+mid; ++k,w=1ll*w*Wn%mod)
				a[k+mid]=a[k]+mod-(t=1ll*a[k+mid]*w%mod), Mod(a[k+mid]),
				a[k]+=t, Mod(a[k]);
	}
	if(opt==-1) for(int i=0,inv=FP(lim,mod-2); i<lim; ++i) a[i]=1ll*a[i]*inv%mod;
}
void DFS1(int x,int fa)
{
	int mx=0; sz[x]=1;
	for(int i=H[x],v; i; i=nxt[i])
		if((v=to[i])!=fa) DFS1(v,x), sz[x]+=sz[v], sz[v]>mx&&(mx=sz[v],son[x]=v);
}
inline void Init(int x,int m)
{
	vis[x]=1; int *fx=f[id[x]=sk[top--]],a=A[x];
	for(int i=0,x=0; i<m; ++i,(x+=a)>=m&&(x-=m)) fx[i]=W[x];
}
inline void Merge(int x,int *fv,int m)
{
	if(!vis[x]) Init(x,m);
	int *fx=f[id[x]];
	for(int i=0; i<m; ++i) fx[i]=1ll*fx[i]*(fv[i]+1)%mod;
}
void DFS2(int x,int fa)
{
	if(son[x]) DFS2(son[x],x);
	else Init(x,m);
	for(int i=H[x],v; i; i=nxt[i])
		if((v=to[i])!=fa&&v!=son[x]) DFS2(v,x);
	int *fx=f[id[x]];
	for(int i=0; i<m; ++i) Ans[i]+=fx[i];
	if(fa) Merge(fa,fx,m);
	sk[++top]=id[x];
}
void Bluestein(const int n)
{
	int n2=n<<1,w=FP(G,(mod-1)/n2); W[0]=1, W[1]=w;
	for(int i=2; i<n2; ++i) W[i]=1ll*W[i-1]*w%mod;
	for(int i=0; i<n; ++i) g[i]=1ll*g[i]*W[1ll*i*i%n2]%mod;
	for(int i=0; i<n2; ++i) h[i]=FP(W[1ll*(n2-1-i)*(n2-1-i)%n2],mod-2);
	int lim=1,l=-1; while(lim<n*3) lim<<=1, ++l;
	for(int i=1; i<lim; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
	NTT(g,lim,1), NTT(h,lim,1);
	for(int i=0; i<lim; ++i) g[i]=1ll*g[i]*h[i]%mod;
	NTT(g,lim,-1);
	for(int i=0,inv=FP(n,mod-2); i<n; ++i) printf("%d ",1ll*inv*g[n2-1-i]%mod*W[1ll*i*i%n2]%mod);
}

int main()
{
//	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);

	const int n=read(),m=read(); ::m=m;
	for(int i=1; i<=n; ++i) A[i]=read();
	for(int i=1; i<n; ++i) AE(read(),read());

	int w=FP(G,(mod-1)/m); W[0]=1, W[1]=w;
	for(int i=2; i<m; ++i) W[i]=1ll*W[i-1]*w%mod;
	for(int i=1; i<S; ++i) sk[++top]=i;
	DFS1(1,0), DFS2(1,0);

	for(int i=0; i<m; ++i) g[i]=Ans[i]%mod;
	int lim=1,l=-1; while(lim<m) lim<<=1, ++l;
	if(lim==m)
	{
		for(int i=1; i<lim; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
		NTT(g,lim,-1);
		for(int i=0; i<m; ++i) printf("%d ",g[i]);
	}
	else Bluestein(m);

	return 0;
}

B.组合数combination(数位DP Lucas)

题目链接

\(Description\)
给定\(n,m,p,l_1,r_1,...,l_n,r_n\),求\(\sum_{i_1=l_1}^{r_1}\sum_{i_2=l_2}^{r_2}...\sum_{i_n=l_n}^{r_n}C_m^{i_1+i_2+...+i_n}mod\ p\)
\(n\leq 7,\ m\leq 10^{18},\ l_i\leq r_i\leq 10^{17},\ p\leq 10\)\(p\)为质数。

\(Solution\)
直接考虑\(Lucas\)

\[\binom{n}{i_1+i_2+...}=\binom{n/p}{(i_1+i_2+...)/p}\times\binom{n\%p}{(i_1+i_2+...)\%p} \]

区间限制可以\(2^n\)容斥成只有上界的限制,然后就是数位DP了(虽然不明显,但是考虑是\(P\)进制各位独立以及\(P=2\)\(Subtask\)应该也可以想到)。因为每进制位上是互不影响的,所以当前贡献就是乘个\(\binom{n\%m}{sum\%p}\),然后处理下一位。
考虑一些简单情况:\(n=2,P=2\),转移时每一位枚举两个数填什么以及是否需要进\(1\)的位即可。状态就记三维\(0/1\):第一二个数是否卡上界、是否进位。
\(n>2\)时,同样每一位枚举每个数填什么即可,上界限制直接记\(2^n\)的状态。
\(P>2\)时,就直接对每一位记进了多少的数。有\(n\)个数就先递归\(n\)次再枚举下一位,就是很暴力的开\(lim\times n\times n\times n\times2^n\)的数组表示第几位、第几个数、这一位前几个数的和是多少、进了多少、上界限制。
发现像\(P=2\)时从高位到低位做,每次转移枚举进了多少不太靠谱,考虑从低位到高位就没这个问题了。只需要处理一下上界的状态:在低位如果有第\(i\)个数超过上界,令\(s[i]=1\);如果在高位第\(i\)个数小于上界,令\(s[i]=0\)。最后如果所有的\(s[i]=0\)就是合法的(没有超上界的数)。
PS:其实也不需要"每次转移枚举进了多少",每一位先枚举\(sum\)是多少,再枚举\(i_1,i_2,...\)填什么,这样就可以从高位往低位转移了...
复杂度...因为有个\(\log_p10^{17}\),要么\(P=2\)要么\(P=7\)最劣吧...
容斥+压状态有个\(4^n\),但是容斥可以去掉,压是否卡上界卡下界。可能同时卡上下界,但是这种情况是不会同时出现的...?所以去掉\(0\)的状态用哈希表存状态就是\(3^n\)的了。

注意最高位的取值\(lim\)要加一,因为最后是可能会再进一位的。

其实会\(P=2\)\(Lucas\)就很好想,但是真这么暴力的吗= = 不敢写.jpg


//19789ms	8004kb
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=7,M=62;

int n,P,lim,bitn[M],A[N][M],C[N][N],Time,f[M][N][N][N][1<<N],vis[M][N][N][N][1<<N];
LL m,L[N],R[N];

inline LL read()
{
	LL now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now;
}
void Divide(int *bit,LL x)
{
	memset(bit,0,lim<<2);
	for(int t=0; x; x/=P) bit[t++]=x%P;
}
int DFS(int x,int num,int sum,int carry,int s)
{
	if(x==lim) return !s;
	if(num==n) return C[bitn[x]][sum]*DFS(x+1,0,carry%P,carry/P,s)%P;
	int &vis=::vis[x][num][sum][carry][s],&ans=f[x][num][sum][carry][s];
	if(vis==Time) return ans;
	vis=Time, ans=0;
	for(int i=P-1; ~i; --i)
	{
		int ss=s;
		if(i>A[num][x]) ss|=1<<num;
		else if(ss>>num&1 && i<A[num][x]) ss^=1<<num;
		bool f=sum+i>=P;
		ans+=DFS(x,num+1,f?sum+i-P:sum+i,carry+f,ss);
	}
	return ans%P;
}

int main()
{
//	freopen("combination.in","r",stdin);
//	freopen("combination.out","w",stdout);

	n=read(),m=read(),P=read();
	for(int i=0; i<P; ++i)
	{
		C[i][0]=C[i][i]=1;
		for(int j=1; j<i; ++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
	}
	LL mx=m;
	for(int i=0; i<n; ++i) L[i]=read(),mx=std::max(mx,R[i]=read());
	for(LL t=1; t<=mx; t*=P,++lim); ++lim;
	Divide(bitn,m);
	int ans=0;
	for(int s=0,l=1<<n; s<l; ++s)
	{
		bool f=0;
		for(int i=0; i<n; ++i)
			if(s>>i&1) f^=1, Divide(A[i],L[i]-1);
			else Divide(A[i],R[i]);
		++Time, ans+=(f?-1:1)*DFS(0,0,0,0,0);
	}
	printf("%d\n",(ans%P+P)%P);

	return 0;
}

C

题目链接




考试代码

A

考试代码:

#include <map>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define mp std::make_pair
#define pr std::pair<int,int>
#define Iter std::map<int,int>::iterator//auto
#define mod 950009857
#define Mod(x) x>=mod&&(x-=mod)
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
#define Add2(x,y) x+y>=m?x+y-m:x+y
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
//typedef unsigned int uint;
const int N=8005,M=58000;

int n,m,A[N],Enum,H[N],nxt[N<<1],to[N<<1];
LL Ans[M];
std::map<int,int> f[N];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now;
}
inline void AE(int u,int v)
{
	to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
	to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
namespace Subtask1
{
	int f[102][152],g[152];
	LL Ans[152];
	void DFS(int x,int fa)
	{
		int *fx=f[x]; fx[A[x]]=1;
		for(int i=H[x],v; i; i=nxt[i])
			if((v=to[i])!=fa)
			{
				DFS(v,x);
				int *fv=f[v]; ++fv[0];
				for(int a=0,v1; a<m; ++a)
					if((v1=f[v][a]))
						for(int b=0,p; b<m; ++b)
							p=Add2(a,b), Add(g[p],1ll*fx[b]*v1%mod);
				for(int a=0; a<m; ++a) fx[a]=g[a], g[a]=0;
			}
//		printf("%d:\n",x);
//		for(int i=0; i<m; ++i) printf("f[%d]=%d\n",i,fx[i]); puts("");
		for(int i=0; i<m; ++i) Ans[i]+=fx[i];
	}
	void Main(int n,int m)
	{
		DFS(1,1);
		for(int i=0; i<m; ++i) printf("%d ",(int)(Ans[i]%mod));
	}
}
void DFS(int x,int fa)
{
	static int g[M];//map
	static pr tmp[M];
	std::map<int,int> &fx=f[x]; fx[A[x]]=1;
	for(int i=H[x],v; i; i=nxt[i])
		if((v=to[i])!=fa)
		{
			DFS(v,x);
			std::map<int,int> &fv=f[v]; ++fv[0];
			int t=0;
			for(Iter it2=fx.begin(); it2!=fx.end(); ++it2)
				if(it2->second) tmp[++t]=mp(it2->first,it2->second);
			int a,v1,p;
			for(Iter it=fv.begin(); it!=fv.end(); ++it)
				if((a=it->first,v1=it->second))
					for(int j=1; j<=t; ++j)
						p=Add2(a,tmp[j].first), Add(g[p],1ll*tmp[j].second*v1%mod);
			for(int a=0; a<m; ++a) if(g[a]) fx[a]=g[a], g[a]=0;
		}
	for(Iter it=fx.begin(); it!=fx.end(); ++it) Ans[it->first]+=it->second;
}

int main()
{
//	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);

	const int n=read(); ::n=n,m=read();
	for(int i=1; i<=n; ++i) A[i]=read();
	for(int i=1; i<n; ++i) AE(read(),read());
	if(n<=100&&m<=150) return Subtask1::Main(n,m),0;

	DFS(1,1);
	for(int i=0; i<m; ++i) printf("%d ",(int)(Ans[i]%mod));
	

	return 0;
}

70分代码:

#include <cstdio>
#include <cctype>
#include <algorithm>
#define G 7
#define invG 135715694
#define mod 950009857
#define Mod(x) x>=mod&&(x-=mod)
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
//#define gc() getchar()
#define MAXIN 500000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=8005,M=58000;

int n,m,A[N],Enum,H[N],nxt[N<<1],to[N<<1],dis[N],pre[N];
int Tot,top,sk[N],id[N],lim,Inv,rev[N],f[2002][32769];
LL Ans[M];
char IN[MAXIN],*SS=IN,*TT=IN;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now;
}
inline void AE(int u,int v)
{
	to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
	to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
inline int FP(int x,int k)
{
	int t=1;
	for(; k; k>>=1,x=1ll*x*x%mod)
		if(k&1) t=1ll*t*x%mod;
	return t;
}
int BFS(int x)
{
	static int q[N];
	int h=0,t=1; q[0]=x, dis[x]=pre[x]=0;
	while(h<t)
	{
		int x=q[h++];
		for(int i=H[x],v; i; i=nxt[i])
			if((v=to[i])!=pre[x]) pre[v]=x, dis[v]=dis[x]+1, q[t++]=v;
	}
	return q[t-1];
}
int FindRoot()
{
	int T=BFS(1),S=BFS(T);
	for(int x=dis[S]>>1; x; --x,S=pre[S]);
	return S;
}
void NTT(int *a,int lim,int opt)
{
	for(int i=1; i<lim; ++i) if(i<rev[i]) std::swap(a[i],a[rev[i]]);
	for(int i=2; i<=lim; i<<=1)
	{
		int mid=i>>1,Wn=FP(~opt?G:invG,(mod-1)/i);
		for(int j=0; j<lim; j+=i)
			for(int k=j,w=1,t; k<j+mid; ++k,w=1ll*w*Wn%mod)
				a[k+mid]=a[k]+mod-(t=1ll*a[k+mid]*w%mod), Mod(a[k+mid]),
				a[k]+=t, Mod(a[k]);
	}
	if(opt==-1)
		for(int i=0,inv=Inv; i<lim; ++i) a[i]=1ll*a[i]*inv%mod;
}
void DFS(int x,int fa)
{
	int p=top?sk[top--]:++Tot,*fx=f[p]; id[x]=p;
	for(int i=0; i<m; ++i) fx[i]=0;
	fx[A[x]]=1, NTT(fx,lim,1);
	for(int i=H[x],v; i; i=nxt[i])
		if((v=to[i])!=fa)
		{
			DFS(v,x);
			int *fv=f[id[v]]; ++fv[0];
			NTT(fv,lim,1);
			for(int j=0; j<m; ++j) fx[j]=1ll*fx[j]*fv[j]%mod;
		}
	sk[++top]=p;
	NTT(fx,lim,-1);
	for(int i=0; i<m; ++i) Ans[i]+=fx[i];
}

int main()
{
	freopen("tree.in","r",stdin);
//	freopen("tree.out","w",stdout);

	const int n=read(),m=read(); ::n=n,::m=m;
	for(int i=1; i<=n; ++i) A[i]=read();
	for(int i=1; i<n; ++i) AE(read(),read());
	int lim=1,l=-1;
	while(lim<m) lim<<=1, ++l;
	for(int i=1; i<lim; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<l);
	::lim=lim, Inv=FP(lim,mod-2), DFS(FindRoot(),0);
	for(int i=0; i<m; ++i) printf("%d ",(int)(Ans[i]%mod));

	return 0;
}

B

数位DP用到了\(C(n,m)为奇数\Leftrightarrow n\&m=m\)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define Mod(x) x>=mod&&(x-=mod)
#define gc() getchar()
typedef long long LL;
const int N=9,LIM=1e9;

LL L[N],R[N];

inline LL read()
{
	LL now=0,f=1;register char c=gc();
	for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now*f;
}
//#define De 0
namespace Subtask4//P==2
{
	const int N=70;
	int cntn,cntx,cnty,bitn[N],bitx[N],bity[N],f[N][8];
	bool vis[N][8];
	int DFS(int x,int s)//limx limy 1:carry
	{
//		De&&printf("x:%d %d,%d,%d\n",x,s&1,(s&2),(s&4));
		if(!x) return (s&4)==0;
		if(vis[x][s]) return f[x][s];
		int ans=0,upx=s&1?bitx[x]:1,upy=s&2?bity[x]:1,car=s&4;
		for(int i=0; i<=upx; ++i)
			for(int j=0; j<=upy; ++j)
				for(int k=0; k<=1; ++k)
				{
					if((car&&i+j+k<2)||(!car&&i+j+k>1)) continue;
					int tmp=i+j+k&1;
					if((bitn[x]&tmp)!=tmp) continue;
//					De&&printf("x:%d i:%d j:%d k:%d val:%d\n",x,i,j,k,DFS(x-1,(s&1&&i==upx)|((s&2&&j==upy)<<1)|(k<<2)));
					ans+=DFS(x-1,(s&1&&i==upx)|((s&2&&j==upy)<<1)|(k<<2));
				}
//		De&&printf("After x:%d %d,%d,%d ans:%d\n",x,s&1,(s&2),(s&4),ans);
		return vis[x][s]=1,f[x][s]=ans&1;
	}
	int Calc(LL x,LL y)
	{
//		De&&printf("\nX:%lld Y:%lld\n",x,y);
		cntx=cnty=0;
		memset(vis,0,sizeof vis);
		memset(bitx,0,sizeof bitx);
		memset(bity,0,sizeof bity);
		for(LL t=x; t; t>>=1) bitx[++cntx]=t&1;
		for(LL t=y; t; t>>=1) bity[++cnty]=t&1;
		int l=std::max(cntn,std::max(cntx,cnty));
//		De&&printf("res: %d %d\n",DFS(l,3),DFS(l,7));
//		if(De) return 0;
		return DFS(l,3);
	}
	void Main(int n,LL m)
	{
		cntn=0, memset(bitn,0,sizeof bitn);
		for(LL x=m; x; x>>=1) bitn[++cntn]=x&1;
		int ans;
		if(n==1) ans=2+Calc(R[1],0)-Calc(L[1]-1,0);
		else ans=32+Calc(R[1],R[2])-Calc(R[1],L[2]-1)-Calc(L[1]-1,R[2])+Calc(L[1]-1,L[2]-1);
		printf("%d\n",ans&1);
	}
}
namespace TEMP
{
	const int N=4e3+5;
	int mod,Ans;
	LL m;
	inline int FP(int x,int k)
	{
		int t=1;
		for(; k; k>>=1,x=x*x%mod)
			if(k&1) t=t*x%mod;
		return t;
	}
	inline int C_(int n,int m)
	{
		if(n<m) return 0;
		int up=1,down=1;
		for(int i=n-m+1; i<=n; ++i) up=up*i%mod;
		for(int i=2; i<=m; ++i) down=down*i%mod;
		return up*FP(down,mod-2)%mod;
	}
	int Lucas(LL n,LL m)
	{
		int ans=1;
		for(; m&&ans; n/=mod,m/=mod) ans=ans*C_(n%mod,m%mod)%mod;
		return ans;
	}
	void DFS(int x,LL s)
	{
		if(s>m) return;
		if(!x) {Ans+=Lucas(m,s)/*C[m][s]*/; return;};
		for(int i=L[x]; i<=R[x]; ++i) DFS(x-1,s+i);
	}
	void Main(int n,LL m,int P)
	{
		TEMP::m=m, mod=P;
		Ans=0, DFS(n,0);
		printf("%d\n",Ans%P);
	}
}/*
2 229 2
49 105
43 152
*/

int main()
{
//	freopen("combination.in","r",stdin);
//	freopen("combination.out","w",stdout);

//	int n=2,m=229,P=2; L[1]=L[2]=0, R[1]=105, R[2]=42;
//	return TEMP::Main(n,m,P),0;

	const int n=read(); const LL m=read(); const int P=read();
	for(int i=1; i<=n; ++i) L[i]=read(),R[i]=read();
	if(n<=2 && P==2) return Subtask4::Main(n,m),0;
	TEMP::Main(n,m,P);
	return 0;

//	int n=2, P=2;
//	for(int m=2; m<=3000; ++m)
//	{
//		for(int i=1; i<=n; ++i) R[i]=rand()%233+2, L[i]=std::max(1ll,std::max(rand()%R[i],R[i]-5000));
//		printf("m:%d L:%d R:%d %d %d\n",m,L[1],R[1],L[2],R[2]);
//		Subtask4::Main(n,m),0;
//		TEMP::Main(n,m,P);
//		puts("");
//	}
	

	return 0;
}

C

另20分的SA写挂了...懒得调.jpg

#include <set>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=5e4+5,BIT=16,INF=0x7fffffff;

int A[N],mx[BIT][N],Log[N];
char s[N],IN[MAXIN],*SS=IN,*TT=IN;
struct Suffix_Array
{
	int sa[N],sa2[N],rk[N],ht[N],tm[N],Log[N],st[16][N];
	inline int LCP(int l,int r)
	{
		if(l>r) std::swap(l,r);
		++l; int k=Log[r-l+1];
		return std::min(st[k][l],st[k][r-(1<<k)+1]);
	}
	inline int LCP2(int l,int r)
	{
		l=rk[l], r=rk[r];
		if(l>r) std::swap(l,r);
		++l; int k=Log[r-l+1];
		return std::min(st[k][l],st[k][r-(1<<k)+1]);
	}
	void Build(const char *s,const int n)
	{
		int m=27,*x=rk,*y=sa2;
		for(int i=0; i<=m; ++i) tm[i]=0;
		for(int i=1; i<=n; ++i) ++tm[x[i]=s[i]-'a'+1];
		for(int i=1; i<=m; ++i) tm[i]+=tm[i-1];
		for(int i=n; i; --i) sa[tm[x[i]]--]=i;
		for(int k=1,p=0; k<n; k<<=1,m=p,p=0)
		{
			for(int i=n-k+1; i<=n; ++i) y[++p]=i;
			for(int i=1; i<=n; ++i) if(sa[i]>k) y[++p]=sa[i]-k;

			for(int i=0; i<=m; ++i) tm[i]=0;
			for(int i=1; i<=n; ++i) ++tm[x[i]];
			for(int i=1; i<=m; ++i) tm[i]+=tm[i-1];
			for(int i=n; i; --i) sa[tm[x[y[i]]]--]=y[i];

			std::swap(x,y), x[sa[1]]=p=1;
			for(int i=2; i<=n; ++i)
				x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?p:++p;
			if(p>=n) break;
		}
		for(int i=1; i<=n; ++i) rk[sa[i]]=i;
		ht[1]=0;
		for(int i=1,k=0; i<=n; ++i)
		{
			if(rk[i]==1) continue;
			if(k) --k;
			int p=sa[rk[i]-1];
			while(i+k<=n && p+k<=n && s[i+k]==s[p+k]) ++k;
			ht[rk[i]]=k;
		}
//		for(int i=1; i<=n; ++i) printf("%d:sa:%d ht:%d rk:%d\n",i,sa[i],ht[i],rk[i]);
		st[0][1]=ht[1];
		for(int i=2; i<=n; ++i) Log[i]=Log[i>>1]+1, st[0][i]=ht[i];
		for(int j=1; j<=Log[n]; ++j)
			for(int t=1<<j-1,i=n-t; i; --i)
				st[j][i]=std::min(st[j-1][i],st[j-1][i+t]);
	}
}sa;

inline int read()
{
	int now=0;register char c=gc();
	for(;!isdigit(c);c=gc());
	for(;isdigit(c);now=now*10+c-48,c=gc());
	return now;
}
inline void Init_ST(int n)
{
	for(int i=2; i<=n; ++i) Log[i]=Log[i>>1]+1;
	for(int j=1; j<=Log[n]; ++j)
		for(int t=1<<j-1,i=n-t; i; --i)
			mx[j][i]=std::max(mx[j-1][i],mx[j-1][i+t]);
}
inline int Query(int l,int r,int x)
{
	if(l==r) return INF;
	if(l>r) std::swap(l,r);
	r+=x-1;
	int k=Log[r-l+1];
//	printf("Query(%d,%d)=%d\n",l,r,std::max(mx[k][l],mx[k][r-(1<<k)+1]));
	return std::max(mx[k][l],mx[k][r-(1<<k)+1]);
}
namespace Subtask1
{
	void Solve(const int n)
	{
		int ans=INF,ok=0,L=read(),R=read(),x=read();
		R=R-x+1;
		for(int i=L; i<R; ++i)
			for(int j=i+1; j<=R; ++j)
				if(sa.LCP2(i,j)>=x) ok=1, ans=std::min(ans,Query(i,j,x));
		printf("%d\n",ok?ans:-1);
	}
	void Main(int n,int m)
	{
		for(int T=1; T<=m; ++T) Solve(n);
	}
}
namespace Subtask2
{
	#define In(x,l,r) (l<=x&&x<=r)
	void Solve(const int n)
	{
		std::set<int> st;
		int L=read(),R=read(),x=read();
		R=R-x+1;
		if(R<=L) {puts("-1"); return;}
		int l=1,ans=INF,ok=0;
//		printf("L:%d R:%d x:%d\n",L,R,x);
		for(int r=1; r<=n; ++r)
		{
			while(l<r && sa.LCP(l,r)<x)
			{
				if(In(sa.sa[l],L,R)) st.erase(sa.sa[l]);
				++l;
			}
			if(!In(sa.sa[r],L,R)) continue;
			std::set<int>::iterator it=st.upper_bound(r);
			if(it!=st.end()) ok=1, ans=std::min(ans,Query(sa.sa[r],*it,x));
			if(it!=st.begin()) --it, ok=1, ans=std::min(ans,Query(sa.sa[r],*it,x));
			st.insert(sa.sa[r]);
		}
		printf("%d\n",ok?ans:-1);
	}
	void Main(int n,int m)
	{
		for(int T=1; T<=m; ++T) Solve(n);
	}
}
namespace Subtask3
{
	void Solve(const int n)
	{
		std::set<int> st;
		int L=read(),R=read(),x=read();
		R=R-x+1;
		if(R<=L) {puts("-1"); return;}
		int l=1;
		for(int r=1; r<=n; ++r)
		{
			while(l<r && sa.LCP(l,r)<x)
			{
				if(In(sa.sa[l],L,R)) st.erase(sa.sa[l]);
				++l;
			}
			if(!In(sa.sa[r],L,R)) continue;
			if(!st.empty()) {printf("%d\n",A[1]); return;} 
			st.insert(sa.sa[r]);
		}
		puts("-1");
	}
	void Main(int n,int m)
	{
		for(int T=1; T<=m; ++T) Solve(n);
	}
}

int main()
{
//	freopen("string.in","r",stdin);
//	freopen("string.out","w",stdout);

	const int n=read(),m=read();
	scanf("%s",s+1);
	for(int i=1; i<=n; ++i) mx[0][i]=A[i]=read();
	Init_ST(n), sa.Build(s,n);
	if(n<=100) return Subtask1::Main(n,m),0;
	if(n<=1000) return Subtask2::Main(n,m),0;
	Subtask3::Main(n,m);
	

	return 0;
}
posted @ 2019-03-10 08:47  SovietPower  阅读(206)  评论(0编辑  收藏  举报