数学杂题 ☆ 多项式 Solution Set

放了各种杂题。

2022.6.15

NOI2014 随机数生成器

先模拟,然后做个普及组贪心,维护每行能选的左右端点。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<18],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<18,stdin),p1==p2)?EOF:*p1++)
int read()
{
	int x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(int x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
int x0,A,B,C,D;
int rnd[25000005],seq[25000005],L[5005],R[5005];
int n,m,q;
int main(){
	x0=read(),A=read(),B=read(),C=read(),D=read();
	rnd[0]=x0;
	n=read(),m=read(),q=read();
	for(int i=1;i<=n*m;++i)
	{
		LL t=LL(A)*rnd[i-1]*rnd[i-1]+LL(B)*rnd[i-1]+C;
		rnd[i]=t%D;
	}
	for(int i=1;i<=n*m;++i)	seq[i]=i;
	for(int i=1;i<=n*m;++i)	swap(seq[i],seq[rnd[i]%i+1]);
	for(int i=1;i<=q;++i)
	{
		int u=read(),v=read();
		swap(seq[u],seq[v]);
	}
	#define P rnd
	for(int i=1;i<=n;++i)	for(int j=1;j<=m;++j)	P[seq[(i-1)*m+j]]=(i-1)*m+j;
	for(int i=1;i<=n;++i)	L[i]=1,R[i]=m;
	for(int i=1;i<=n*m;++i)
	{
		int p=P[i];
		int x=(p-1)/m+1,y=p-(x-1)*m;
		if(L[x]<=y && y<=R[x])
		{
			write(i),putchar(' ');
			for(int j=1;j<=n;++j)
			{
				if(j==x)	continue;
				if(j<x)	R[j]=min(R[j],y);
				else	L[j]=max(L[j],y);
			}
		}
	}
	return 0;
}

CF923E Perpetual Subtraction

矩阵对角化板子题。

首先你可以写成一个线性变换的形式(虽然我又没看出来,菜了)。然后因为要求 \(m\) 次方所以考虑对角化。注意到这个矩阵的特征值很好找,特征矩阵很有特色(可以通过手算找规律,容易发现是一个组合数加上三角矩阵的形式,带一定的 \(-1\) 系数),这样就最终可以写成两个减法卷积的形式。

注意 \(E\)\(E^{-1}\) 的运算顺序。

/*
他决定要“格”院子里的竹子。于是他搬了一条凳子坐在院子里,面对着竹子硬想了七天,结果因为头痛而宣告失败。
DONT NEVER AROUND . //
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<21],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
const int MOD=998244353;
int read()
{
	int x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
int readMod()
{
	LL x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x%(MOD-1);
}
void write(int x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
inline int Add(int u,int v){return u+v>=MOD?u+v-MOD:u+v;}
inline int Sub(int u,int v){return u-v>=0?u-v:u-v+MOD;}
inline int Mul(int u,int v){return LL(u)*LL(v)%MOD;}
int QuickPow(int x,int p)
{
	if(p<0)	p+=MOD-1;
	int ans=1,base=x;
	while(p)
	{
		if(p&1)	ans=Mul(ans,base);
		base=Mul(base,base);
		p>>=1;
	}
	return ans;
}
typedef vector<int> Poly;
#define len(x) (int(x.size()))
const int GG=3,Gi=(MOD+1)/GG;
int rev[400005];
int fac[400005],ifac[400005];
inline int inv(int x){return x==0?0:Mul(ifac[x],fac[x-1]);}
void init(int up)
{
	fac[0]=1;
	for(int i=1;i<=up;++i)	fac[i]=Mul(fac[i-1],i);
	ifac[up]=QuickPow(fac[up],MOD-2);
	for(int i=up-1;~i;--i)	ifac[i]=Mul(ifac[i+1],i+1);
}
inline void makeRev(int lim){for(int i=0;i<lim;++i)	rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));}
void NTT(Poly &r,int flag)
{
	for(int i=0;i<len(r);++i)	if(i<rev[i])	swap(r[i],r[rev[i]]);
	for(int p=2;p<=len(r);p<<=1)
	{
		int len=p>>1;
		int w=QuickPow(flag?GG:Gi,(MOD-1)/p);
		for(int k=0;k<len(r);k+=p)
		{
			int cn=1;
			for(int i=k;i<k+len;++i)
			{
				int dif=Mul(r[i+len],cn);
				r[i+len]=Sub(r[i],dif);
				r[i]=Add(r[i],dif);
				cn=Mul(cn,w);
			}
		}
	}
	if(flag==0)
	{
		int inv=QuickPow(len(r),MOD-2);
		for(int i=0;i<len(r);++i)	r[i]=Mul(r[i],inv);
	}
}
Poly operator + (Poly F,int v){F[0]=Add(F[0],v);return F;}
Poly operator + (int v,Poly F){F[0]=Add(F[0],v);return F;}
Poly operator - (Poly F,int v){F[0]=Sub(F[0],v);return F;}
Poly operator - (int v,Poly F){F[0]=Sub(F[0],v);return F;}
Poly operator * (Poly F,int v){for(int i=0;i<len(F);++i)	F[i]=Mul(F[i],v);return F;}
Poly operator * (int v,Poly F){for(int i=0;i<len(F);++i)	F[i]=Mul(F[i],v);return F;}
Poly operator + (Poly F,Poly G)
{
	Poly ret;
	int len=max(len(F),len(G));
	F.resize(len),G.resize(len),ret.resize(len);
	for(int i=0;i<len;++i)	ret[i]=Add(F[i],G[i]);
	return ret;
}
Poly operator - (Poly F,Poly G)
{
	Poly ret;
	int len=max(len(F),len(G));
	F.resize(len),G.resize(len),ret.resize(len);
	for(int i=0;i<len;++i)	ret[i]=Sub(F[i],G[i]);
	return ret;
}
Poly operator * (Poly F,Poly G)
{
	Poly ret;
	int len=len(F)+len(G)-1,lim=1;
	while(lim<=len)	lim<<=1;
	F.resize(lim),G.resize(lim),ret.resize(lim);
	makeRev(lim);
	NTT(F,1),NTT(G,1);
	for(int i=0;i<lim;++i)	ret[i]=Mul(F[i],G[i]);
	NTT(ret,0);
	ret.resize(len);
	return ret;
}
int main(){
	init(400000);
	Poly F,G;
	int n=read(),m=readMod();
	F.resize(++n);
	for(int i=0;i<n;++i)	F[i]=Mul(fac[i],read());
	G.resize(n);
	for(int i=0;i<n;++i)	G[i]=ifac[i];
	reverse(F.begin(),F.end());
	F=F*G,F.resize(n);
	reverse(F.begin(),F.end());
	for(int i=0;i<n;++i)	F[i]=Mul(F[i],QuickPow(inv(i+1),m)),F[i]=(i&1)?(MOD-F[i])%MOD:F[i];
	reverse(F.begin(),F.end());
	F=F*G,F.resize(n);
	reverse(F.begin(),F.end());
	for(int i=0;i<n;++i)	F[i]=Mul(F[i],ifac[i]),F[i]=(i&1)?(MOD-F[i])%MOD:F[i],write(F[i]),putchar(' ');
	return 0;
}

CF Gym 103415K Nagus Night

这个题竟然没自己做出来,我真的,😅。

首先算全集,减去 \(\gcd\) 不满足限制的,和 \(\gcd\) 满足限制 \(\operatorname{lcm}\) 不满足限制的。

前面两个都很简单就略过,主要是第三个。记 \(f(i,j)\)\(\gcd(S) = i,\operatorname{lcm} = j\) 的贡献,容易发现这个可以直接 \(O(m \ln m)\) 枚举。并且发现 \(f(i,j) = i^n f(1, \frac{j}{i})\)。显然如果满足 \(f\) 的限制那么 \(S\) 也满足限制。那么拆开质因数贡献,里面也是类似于容斥的形式(全集,减去没有 \(0\) 的,减去没有 \(x_p\) 的,加上两个都没有的)。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<18],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<18,stdin),p1==p2)?EOF:*p1++)
int read()
{
	int x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(int x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
const int MOD=998244353;
inline int Add(int x,int y){return x+y>=MOD?x+y-MOD:x+y;}
inline int Sub(int x,int y){return x<y?x-y+MOD:x-y;}
inline int Mul(int x,int y){return 1ll*x*y%MOD;}
int QuickPow(int x,int p)
{
	int ans=1,base=x;
	while(p)
	{
		if(p&1)	ans=Mul(ans,base);
		base=Mul(base,base);
		p>>=1;
	}
	return ans;
}
int n,m,p,q;
int SolveA();
int SolveB();
int SolveC();
int main(){
	n=read(),m=read(),p=read(),q=read();
	write(Sub(SolveA(),Add(SolveB(),SolveC())));
	return 0;
}
int SolveA(){return QuickPow(Mul(Mul(m,m+1),(MOD+1)/2),n);}
int SolveB()
{
	static int f[200005];
	for(int i=1;i<=m;++i)	f[i]=Mul(QuickPow(i,n),QuickPow(Mul(Mul(m/i,m/i+1),(MOD+1)/2),n));
	for(int i=m;i>=1;--i)	for(int j=2*i;j<=m;j+=i)	f[i]=Sub(f[i],f[j]);
	int ret=0;
	for(int i=q+1;i<=m;++i)	ret=Add(ret,f[i]);
	return ret;
}
bool vis[200005];
int prime[200005],cnt;
int mpr[200005];
void hisa(int up)
{
	mpr[1]=1;
	for(int i=2;i<=up;++i)	mpr[i]=up;
	for(int i=2;i<=up;++i)
	{
		if(!vis[i])	prime[++cnt]=i,mpr[i]=i;
		for(int j=1;j<=cnt && prime[j]*i<=up;++j)
		{
			vis[prime[j]*i]=true;
			mpr[prime[j]*i]=min(mpr[prime[j]*i],prime[j]);
		}
	}
}
int SolveC()
{
	static int f[200005];
	hisa(m);
	for(int i=1;i<=m;++i)
	{
		int x=i;
		f[i]=1;
		while(x^1)
		{
			int t=x,P=mpr[x],tot=0;
			while(mpr[t]==P)	++tot,t/=P;
			x=t;
			int a=0,b=0,c=0,d=0;
			for(int j=0;j<tot;++j)	c=Add(c,QuickPow(P,j));
			a=Add(c,QuickPow(P,tot));
			b=a-1,d=c-1;
			a=QuickPow(a,n);
			b=QuickPow(b,n);
			c=QuickPow(c,n);
			d=QuickPow(d,n);
			f[i]=Mul(f[i],Sub(Add(a,d),Add(b,c)));
		}
	}
	int ret=0;
	for(int i=1;i<=q;++i)	for(int j=i;j<p;j+=i)	ret=Add(ret,Mul(QuickPow(i,n),f[j/i]));
	return ret;
}

CF Gym 103415J Cafeteria

不写成矩阵转移形式,我真的,😅。我都不好说是我变蠢了还是变懒了。

容易写成矩阵转移形式,变成前缀逆和前缀积。容易发现铁 T 无疑。

考虑维护两个矩阵的左右乘,这个分析一下能出来怎么转移的。

最后回答询问的时候我们只需要求出一行一列就好了,做向量乘。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
char buf[1<<18],*p1=buf,*p2=buf;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<18,stdin),p1==p2)?EOF:*p1++)
int read()
{
	int x=0;
	char c=getchar();
	while(c<'0' || c>'9')	c=getchar();
	while(c>='0' && c<='9')	x=(x<<1)+(x<<3)+(c^'0'),c=getchar();
	return x;
}
void write(int x)
{
	if(x>9)	write(x/10);
	putchar(x%10+'0');
}
const int MOD=998244353;
inline int Add(int x,int y){return x+y>=MOD?x+y-MOD:x+y;}
inline int Sub(int x,int y){return x<y?x-y+MOD:x-y;}
inline int Mul(int x,int y){return 1ll*x*y%MOD;}
int QuickPow(int x,int p)
{
	int ans=1,base=x;
	while(p)
	{
		if(p&1)	ans=Mul(ans,base);
		base=Mul(base,base);
		p>>=1;
	}
	return ans;
}
int n,m,p,q;
int SolveA();
int SolveB();
int SolveC();
int main(){
	n=read(),m=read(),p=read(),q=read();
	write(Sub(SolveA(),Add(SolveB(),SolveC())));
	return 0;
}
int SolveA(){return QuickPow(Mul(Mul(m,m+1),(MOD+1)/2),n);}
int SolveB()
{
	static int f[200005];
	for(int i=1;i<=m;++i)	f[i]=Mul(QuickPow(i,n),QuickPow(Mul(Mul(m/i,m/i+1),(MOD+1)/2),n));
	for(int i=m;i>=1;--i)	for(int j=2*i;j<=m;j+=i)	f[i]=Sub(f[i],f[j]);
	int ret=0;
	for(int i=q+1;i<=m;++i)	ret=Add(ret,f[i]);
	return ret;
}
bool vis[200005];
int prime[200005],cnt;
int mpr[200005];
void hisa(int up)
{
	mpr[1]=1;
	for(int i=2;i<=up;++i)	mpr[i]=up;
	for(int i=2;i<=up;++i)
	{
		if(!vis[i])	prime[++cnt]=i,mpr[i]=i;
		for(int j=1;j<=cnt && prime[j]*i<=up;++j)
		{
			vis[prime[j]*i]=true;
			mpr[prime[j]*i]=min(mpr[prime[j]*i],prime[j]);
		}
	}
}
int SolveC()
{
	static int f[200005];
	hisa(m);
	for(int i=1;i<=m;++i)
	{
		int x=i;
		f[i]=1;
		while(x^1)
		{
			int t=x,P=mpr[x],tot=0;
			while(mpr[t]==P)	++tot,t/=P;
			x=t;
			int a=0,b=0,c=0,d=0;
			for(int j=0;j<tot;++j)	c=Add(c,QuickPow(P,j));
			a=Add(c,QuickPow(P,tot));
			b=a-1,d=c-1;
			a=QuickPow(a,n);
			b=QuickPow(b,n);
			c=QuickPow(c,n);
			d=QuickPow(d,n);
			f[i]=Mul(f[i],Sub(Add(a,d),Add(b,c)));
		}
	}
	int ret=0;
	for(int i=1;i<=q;++i)	for(int j=i;j<p;j+=i)	ret=Add(ret,Mul(QuickPow(i,n),f[j/i]));
	return ret;
}
posted @ 2022-06-15 20:33  SyadouHayami  阅读(79)  评论(0编辑  收藏  举报

My Castle Town.