• 数学杂题 ☆ 多项式 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;
    }
    
  • 相关阅读:
    项目管理5大过程9大知识域44个定义
    linux centos6.5 修改ip地址
    .Net 6 已知问题集
    第二次阅读作业——程志
    采访大四学长整理笔记
    c#
    团队作业三两感想 by 程志
    搞定3G上网
    高焕堂Android應用框架原理與程式設計代码补遗(一)
    要素类属性内容全角换半角
  • 原文地址:https://www.cnblogs.com/amagaisite/p/16379741.html
Copyright © 2020-2023  润新知