JSCPC,我该带什么板子?

计算几何(来源

具体包括:
点、线、面、向量
多边形:面积、判断点在多边形内(射线法与二分法),判断多边形相离
凸包:Andrew算法 闵可夫斯基和
旋转卡壳
半平面交
圆:三点确定一圆、最小圆覆盖

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8;
const double Pi=acos(-1.0);
const int N=3e5+10;
inline int dcmp(double x){return (x<-eps)?-1:(x>eps?1:0);}
inline double Abs(double x){return x*dcmp(x);}

namespace CG{
	struct pt{
		double x,y;pt(double _x=0,double _y=0){x=_x;y=_y;}
		inline void read(){scanf("%lf%lf",&x,&y);}
	};
	inline bool cmpx(const pt &a,const pt &b){return (a.x!=b.x)?a.x<b.x:a.y<b.y;}
	
	typedef pt vec;
	inline double Len(const vec &a){return sqrt(a.x*a.x+a.y*a.y);}//模长
	inline double angle(const vec &a){return atan2(a.y,a.x);}
	inline vec operator +(const vec &a,const vec &b){return vec(a.x+b.x,a.y+b.y);}
	inline vec operator -(const vec &a,const vec &b){return vec(a.x-b.x,a.y-b.y);}
	inline vec operator *(const vec &a,double b){return vec(a.x*b,a.y*b);}
	inline vec operator /(const vec &a,double b){return vec(a.x/b,a.y/b);}
		
	inline double operator *(const vec &a,const vec &b){return a.x*b.x+a.y*b.y;}//点积 
	inline double operator ^(const vec &a,const vec &b){return a.x*b.y-a.y*b.x;}//叉积 
		 
	inline vec rotate(vec a,double theta){//将点或向量a绕原点(向量是顶点)逆时针旋转theta的弧度 
		double x=a.x*cos(theta)-a.y*sin(theta);
		double y=a.x*sin(theta)+a.y*cos(theta);
		return pt(x,y); 
	}
	inline vec rotate_90(vec a){return pt(a.y,-a.x);}
	inline pt rotate_P(pt a,pt b,double theta){return rotate(a-b,theta)+b;}//将点a绕点b逆时针旋转theta 
		 
	//命名技巧:点P(point),线段S(segment),射线R(ray),直线L(line) 	 
	struct line{
		pt s,t;
		line(pt _s=pt(0,0),pt _t=pt(0,0)){s=_s;t=_t;}
	};
	inline double maxx(const line &L){return max(L.s.x,L.t.x);}
	inline double maxy(const line &L){return max(L.s.y,L.t.y);}
	inline double minx(const line &L){return min(L.s.x,L.t.x);}
	inline double miny(const line &L){return min(L.s.y,L.t.y);} 
	inline double ang(const line &L){return angle(L.t-L.s);}
	
	inline bool operator <(const line &a,const line &b){
		double a1=angle(a.t-a.s),a2=angle(b.t-b.s);
		if(dcmp(a2-a1)!=0) return dcmp(a2-a1)>0;
		return dcmp((b.t-a.s)^(a.t-a.s))>0;
	}
	inline bool operator ==(pt a,pt b){return (!dcmp(a.x-b.x))&&(!dcmp(a.y-b.y));}
	inline double dis_PP(pt a,pt b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}//点a与点b间的距离 
	inline bool judge_PL(pt a,line b){return !dcmp((a-b.s)^(b.t-b.s));}//判断点是否在直线上
	inline bool judge_PS(pt a,line b){return (!dcmp((a-b.s)^(b.t-b.s)))&&(dcmp((a-b.s)*(a-b.t))<=0);}//判断点是否在线段上
	 
	inline pt Footprint(pt a,line b){//点A关于直线ST的垂足
		pt x=a-b.s,y=a-b.t,z=b.t-b.s;
		double s1=x*z,s2=-1.0*(y*z);//分别求出AS,AT关于ST的投影
		return b.s+z*(s1/(s1+s2)); 
	}
	inline pt mirror(pt a,line b){return a+(Footprint(a,b)-a)*2.0;}//点a关于直线b的对称点 
	inline double dis_PL(pt a,line b){return Abs((a-b.s)^(a-b.t))/Len(b.t-b.s); }//点与直线的距离:面积除以底边长 
	inline double dis_PS(pt a,line b){//点与线段的距离
		pt x=a-b.s,y=a-b.t,z=b.t-b.s;
		if(dcmp(x*z)<0) return Len(x);//距离左端点最近
		if(dcmp(y*z)>0) return Len(y);//距离右端点最近
		return dis_PL(a,b);  
	}
	inline pt point_PS(pt a,line b){//点a在线段b上距离最近的点
		pt x=a-b.s,y=a-b.t,z=b.t-b.s;
		if(dcmp(x*z)<0) return b.s;//距离左端点最近
		if(dcmp(y*z)>0) return b.t;//距离右端点最近
		return Footprint(a,b);  
	}
		 
	inline pt cross_LL(line a,line b){//直线的交点 
		pt x=a.t-a.s,y=b.t-b.s,z=a.s-b.s;
		return a.s+x*((y^z)/(x^y)); 
	}
	inline bool judge_cross_SL(line a,line b){//判断线段a与直线b是否相交 
		if(!dcmp((a.t-a.s)^(b.t-b.s))) return false; 
		return judge_PS(cross_LL(a,b),a);//看交点是否在线段上即可 
	}
	inline bool judge_cross_SS(line a,line b){//判断两线段是否相交 
		if(maxx(a)<minx(b)||maxy(a)<miny(b)) return false;
		if(maxx(b)<minx(a)||maxy(b)<miny(a)) return false;
		double s1=(a.t-a.s)^(b.s-a.s),s2=(a.t-a.s)^(b.t-a.s);
		double s3=(b.t-b.s)^(a.s-b.s),s4=(b.t-b.s)^(a.t-b.s);
		return dcmp(s1)*dcmp(s2)<=0&&dcmp(s3)*dcmp(s4)<=0;//a的端点在b的两侧且b的端点在a的两侧 
	}
}
using namespace CG;	 

namespace Polygon{//多边形 
	struct polygon{
		vector<pt> pts;
		inline pt& operator [](int x){return pts[x];}
		inline void read(int n){
			pt cur;
			for(int i=0;i<n;++i) cur.read(),pts.push_back(cur);
		}
		inline void clear(){pts.clear();}
		inline int nxt(int x){return x<pts.size()-1?x+1:0;}
		inline int include(pt p){//点在多边形上:0:在多边形外,1:在多边形内,2:在多边形的边上 
			int cnt=0;
			for(int i=0;i<pts.size();++i){
				pt s=pts[i],t=pts[nxt(i)];
				line L=line(s,t);
				if(judge_PS(p,L)) return 2;
				if(dcmp(p.y-miny(L))>=0&&dcmp(maxy(L)-p.y)>0){
					double nx=s.x+((p.y-s.y)/(t.y-s.y)*(t.x-s.x));
					if(dcmp(nx-p.x)>0) cnt++;
				}
			}
			return cnt&1;
		}
		
		inline double area(){//面积 
			double ans=0;
			for(int i=1;i<pts.size()-1;++i) ans+=(pts[i]-pts[0])^(pts[nxt(i)]-pts[0]);
			return Abs(ans)/2;
		}
		inline double peri(){//周长 
			double ans=0;
			for(int i=0;i<pts.size();++i) ans+=dis_PP(pts[i],pts[nxt(i)]);
			return ans;
		}
		inline bool Left(pt x,pt l,pt r){return dcmp((l-x)^(r-x))<=0; }//xl是否在xr左侧 
		inline void rever(){reverse(pts.begin(),pts.end());}//转顺时针为逆时针 
		inline int include_bs(pt p){//二分法判断点是否在多边形内 
			int n=pts.size();
			if(!Left(pts[0],p,pts[1])) return 0;
			if(!Left(pts[0],pts[n-1],p)) return 0;
			if(judge_PS(p,line(pts[0],pts[1]))) return 2;
			if(judge_PS(p,line(pts[0],pts[n-1]))) return 2;
			int l=1,r=n-2,ans=1;
			while(l<=r){
				int mid=(l+r)>>1;
				if(!Left(pts[0],pts[mid],p)) l=mid+1,ans=mid;
				else r=mid-1;
			}
			if(!Left(pts[ans],p,pts[nxt(ans)])) return 0;
			if(judge_PS(p,line(pts[ans],pts[nxt(ans)]))) return 2;
			return 1;
		}
		inline void insert(pt p){pts.push_back(p);}
	};
	inline bool disjoint(polygon A,polygon B){//多边形AB是否相离
		for(int i=0;i<A.pts.size();++i){
			line x=line(A[i],A[A.nxt(i)]);
			for(int j=0;j<B.pts.size();++j){
				line y=line(B[j],B[B.nxt(j)]);
				if(judge_cross_SS(x,y)) return false;
			}
		}
		if(A.include_bs(B[0])) return false;
		if(B.include_bs(A[0])) return false;
	 	return true;
	}
}
using namespace Polygon;

namespace Hull{// 凸包、旋转卡壳、半平面交、闵可夫斯基和 
	inline void Andrew(polygon &p){//Andrew算法求凸包 
		vector<pt> q(p.pts.size()<<1);
		sort(p.pts.begin(),p.pts.end(),cmpx);
		int top=-1,n=p.pts.size();
		q[++top]=p[0];
		for(int i=1;i<n;++i){
			while(top&&dcmp((q[top-1]-q[top])^(p[i]-q[top]))>=0) top--;
			q[++top]=p[i];
		}
		int now=top;
		for(int i=n-2;i>=0;--i){
			while(top>now&&dcmp((q[top-1]-q[top])^(p[i]-q[top]))>=0) --top;
			q[++top]=p[i];
		}
		if(n>1) --top;
		p.clear();
		for(int i=0;i<=top;++i) p.insert(q[i]);
	}
	inline double S(const pt &x,const pt &y,const pt &z){return Abs((y-x)^(z-x));} 
	inline double diam(polygon &p){//旋转卡壳求凸包直径 
		int n=p.pts.size();double ans=0;
		for(int i=0,j=1;i<n;++i){
			for(;;j=p.nxt(j))
				if(dcmp(S(p[j],p[i],p[p.nxt(i)])-S(p[p.nxt(j)],p[i],p[p.nxt(i)]))>=0) break;
			ans=max(ans,dis_PP(p[j],p[i]));ans=max(ans,dis_PP(p[j],p[p.nxt(i)]));
		} 
		return ans;
	}
	inline polygon SI(vector<line> q){//半平面交算法 S&I 
		int n=q.size();
		sort(q.begin(),q.end());
		vector<line> li(n+1),L(n+1);vector<pt> p(n+1);
		int len=0;
		for(int i=0;i<n;++i){
			if(i>0&&!dcmp(ang(q[i])-ang(q[i-1]))) continue;
			L[++len]=q[i];
		}
		int l=1,r=0;
		for(int i=1;i<=len;++i){
			while(l<r&&dcmp((L[i].t-p[r])^(L[i].s-p[r]))>0) --r;
			while(l<r&&dcmp((L[i].t-p[l+1])^(L[i].s-p[l+1]))>0) ++l;
			li[++r]=L[i];if(r>l) p[r]=cross_LL(li[r],li[r-1]); 
		}
		while(l<r&&dcmp((li[l].t-p[r])^(li[l].s-p[r]))>0) --r;
		while(l<r&&dcmp((li[r].t-p[l+1])^(li[r].s-p[l+1]))>0) ++l;
		
		p[r+1]=cross_LL(li[r],li[l]),++r;
		polygon P;
		for(int j=l+1;j<=r;++j) P.insert(p[j]);
		return P;
	} 
	inline polygon merge(polygon A,polygon B){//闵可夫斯基和 
		int n=A.pts.size(),m=B.pts.size(),tot1=0,tot2=0;	
		vector<pt> p(n+1),q(m+1);
		for(int i=1;i<n;++i) p[++tot1]=A[i]-A[i-1];p[++tot1]=A[0]-A[n-1];
		for(int i=1;i<m;++i) q[++tot2]=B[i]-B[i-1];q[++tot2]=B[0]-B[m-1];
		int i=1,j=1,tot=0;pt last=pt(0,0);
		polygon C;C.pts.resize(n+m+1);C[0]=last=A[0]+B[0];
		while(i<=n&&j<=m){
			if(dcmp(p[i]^q[j])>=0) C[++tot]=last+p[i++],last=C[tot];
			else C[++tot]=last+q[j++],last=C[tot];
		}	
		while(i<=n) C[++tot]=last+p[i++],last=C[tot];
		while(j<=m) C[++tot]=last+q[j++],last=C[tot];
		Andrew(C);
		return C;
	}
}
using Hull::Andrew;
using Hull::diam;
using Hull::merge;

namespace Circle{//圆:三点确定一圆、最小圆覆盖 
	struct circle{
		pt o;double r;
		circle(pt _o=pt(0,0),double _r=0){o=_o;r=_r;}
		circle(pt A,pt B,pt C){//三点确定一圆 
			pt D=(A+B)/2,E=(B+C)/2;
			o=cross_LL(line(D,D+rotate_90(B-A)),line(E,E+rotate_90(C-B)));
			r=dis_PP(o,A);
		}
		inline bool include(pt p){return dcmp(r-dis_PP(p,o))>=0;}//点在圆内
		inline void print(int x){
			printf("%.*lf\n",x,r);
			printf("%.*lf %.*lf",x,o.x,x,o.y);
		}
	};		
	inline circle mincov(const vector<pt> &p){//最小圆覆盖 
		int n=p.size();
		circle c=circle(0,0);
		for(int i=0;i<n;++i){
			if(!c.include(p[i])){
				c=circle(p[i],0);
				for(int j=0;j<i;++j){
					if(!c.include(p[j])){
						c=circle((p[i]+p[j])/2.0,dis_PP(p[i],p[j])/2.0);
						for(int k=0;k<j;++k)
							if(!c.include(p[k])) c=circle(p[i],p[j],p[k]);
					}
				}		
			}
		} 
		return c;
	}
} 
using namespace Circle;

字符串

SA

其中,\(sa[i]\) 表示将所有后缀排序后第 \(i\) 小的后缀的编号,也是所说的后缀数组;
\(rk[i]\) 表示后缀 \(i\) 的排名,是重要的辅助数组,也是排列 \(sa\) 的逆排列。

#include<bits/stdc++.h>
using namespace std;
char s[1000005];
int y[1000005],x[1000005],c[1000005],sa[1000005],rk[1000005],height[1000005],wt[30];
int n,m;
void SA(){
	for(int i=1;i<=n;i++)x[i]=s[i],c[x[i]]++;
	for(int i=2;i<=m;i++)c[i]+=c[i-1];
	for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
	for(int k=1;k<=n;k<<=1){
		int num=0;
		for(int i=n-k+1;i<=n;i++)y[++num]=i;
		for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
		for(int i=1;i<=m;i++)c[i]=0;
		for(int i=1;i<=n;i++)c[x[i]]++;
		for(int i=2;i<=m;i++)c[i]+=c[i-1];
		for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
		swap(x,y);
		x[sa[1]]=1;num=1;
		for(int i=2;i<=n;i++){
			if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k])num++;
			x[sa[i]]=num;
		}
		if(num==n)break;
		m=num;
	}
	for(int i=1;i<=n;i++)cout<<sa[i]<<" ";
} 
int geth(){
	int k=0;
	for(int i=1;i<=n;i++)rk[sa[i]]=i;
	for(int i=1;i<=n;i++){
		if(rk[i]==1)continue;
		if(k)k--;
		int j=sa[rk[i]-1];
		while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k])k++;
		height[rk[i]]=k;
	}
} 
int main(){
	cin>>(s+1);n=strlen(s+1);m=122;
    SA();
}

SAM
以下解决了:给定一个只包含小写字母的字符串 \(S\),求 \(S\) 的所有出现次数不为 \(1\) 的子串的出现次数乘上该子串长度的最大值。

#include<bits/stdc++.h>
using namespace std;
int tot=1,las=1;
long long ans;
int sz[2000010];
vector<int>G[2000010];
struct node{
	int ch[26];
	int len,fa;
	node(){memset(ch,0,sizeof(ch));len=fa=0;}
}am[2000010];
void add(int c){
	int p=las,np=las=++tot;sz[tot]=1;
	am[np].len=am[p].len+1;
	for(;p&&!am[p].ch[c];p=am[p].fa)am[p].ch[c]=np;
	if(!p)am[np].fa=1;
	else{
		int q=am[p].ch[c];
		if(am[q].len==am[p].len+1)am[np].fa=q;
		else{
			int nq=++tot;
			am[nq]=am[q];am[nq].len=am[p].len+1;
			am[q].fa=am[np].fa=nq;
			for(;p&&am[p].ch[c]==q;p=am[p].fa)am[p].ch[c]=nq;
		}
	}
}
void dfs(int u){
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		dfs(v);sz[u]+=sz[v];
	}
	if(sz[u]!=1)ans=max(ans,1ll*sz[u]*am[u].len);
}
string s;
signed main(){
	cin>>s;
	for(int i=0;i<s.size();i++)add(s[i]-'a');
	for(int i=2;i<=tot;i++)G[am[i].fa].push_back(i);
	dfs(1);cout<<ans<<endl;
	return 0;
}

数学

线性乘法逆元:

    inv[1]=1;
    for(int i=2;i<=n;i++)inv[i]=(P-P/i)*inv[P%i]%P;

扩展欧拉定理。以下代码解决了:给定 \(a,m,b\),求 \(a^b\pmod m\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
int a,mod,b,fl;
int ksm(int a,int q){
	int res=1;
	while(q){
		if(q&1)res=res*a%mod;
		a=a*a%mod;
		q>>=1;
	}
	return res;
}
signed main() {
	cin>>a>>mod;a%=mod;
	int m=mod,phi=1;
	for (int i=2;i*i<=m;i++) {
		if(m%i)continue;
		phi*=i-1,m/=i;
		while(m%i==0)phi*=i,m/=i;
	}
	if(m>1)phi*=m-1;
	char ch;
	for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()){
		b=(b<<3)+(b<<1)+(ch-48);
		if(b>=phi)fl=1,b%=phi;
	}
	cout<<ksm(a,fl?b+phi:b)<<endl;
	return 0;
}

exgcd & excrt(模数不互质的同余方程组):

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,a[100005],b[100005];
int ksm(int a,int q,int mod){
	int res=0;
	while(q){
		if(q&1)res=res=(res+a)%mod;
		a=(a+a)%mod;
		q>>=1;
	}
	return res;
}
int exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1,y=0;
		return a;
	}
	int gcd=exgcd(b,a%b,x,y);
	int tmp=x;
	x=y;
	y=tmp-a/b*y;
	return gcd;
}
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++)cin>>b[i]>>a[i];
	int x,y,k;
	int mod=b[1],ans=a[1];
	for(int i=2;i<=n;i++){
		int na=mod,nb=b[i];
		int c=(a[i]-ans%nb+nb)%nb;
		int gcd=exgcd(na,nb,x,y);
		int bg=nb/gcd;
		x=ksm(x,c/gcd,bg);
		ans+=x*mod;
		mod*=bg;
		ans=(ans%mod+mod)%mod;
	}
	cout<<ans<<endl;
	return 0;
}

exBSGS(给定 \(a,p,b\),求满足 \(a^x\equiv b\pmod p\) 的最小自然数 \(x\)):

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int ksm(int a,int q,int P){
	int res=1;a%=P;
	while(q){
		if(q&1)res=res*a%P;
		a=a*a%P;
		q>>=1;
	}
	return res;
}
int phi(int x){
	int res=1;
	for(int i=2;i*i<=x;i++){
		if(x%i)continue;
		int p=1;
		x/=i;
		while(x%i==0)p*=i,x/=i;
		res*=p*(i-1);
	}
	if(x!=1)res*=x-1;
	return res;
}
int BSGS(int a,int b,int P){
	a%=P;b%=P;
	if(b==1)return 0;
	if(P==1)return 1;
	int S=ceil(sqrt(P)),aps=1,lft;
	map<int,int> mp;
	for(int i=0;i<=S;i++){
		mp[aps*b%P]=i;
		if(i!=S)aps=aps*a%P;
	}
	lft=aps;
	for(int i=1;i<=S;i++){
		if(mp.find(lft)!=mp.end())return i*S-mp[lft];
		lft=lft*aps%P;
	}
	return -1;
}
int exBSGS(int a,int b,int P){
	a%=P,b%=P;
	if(b==1||P==1)return 0;
	int d,k=0,dlt=1;
	while((d=__gcd(a,P))>1){
		if(b%d)return -1;
		b/=d;P/=d;
		dlt=dlt*(a/d)%P;k++;
		if(b==dlt)return k;
	}
	int res=BSGS(a,b*ksm(dlt,phi(P)-1,P)%P,P);
	return res<0?-1:res+k;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	int a,p,b;
	while(cin>>a>>p>>b){
		if(a==0&&p==0&&b==0)break;
		int res=exBSGS(a,b,p);
		if(res>-1)cout<<res<<endl;
		else cout<<"No Solution"<<endl;
	}
	return 0;
}

类欧。
以下代码解决了:
给定 \(n,\,a,\,b,\,c\) ,分别求 \(\sum\limits_{i=0}^{n}\left\lfloor \frac{ai+b}{c} \right\rfloor\,,\ \sum\limits_{i=0}^{n}{\left\lfloor \frac{ai+b}{c} \right\rfloor}^2\,,\ \sum\limits_{i=0}^{n}i\left\lfloor \frac{ai+b}{c} \right\rfloor\) ,答案对 \(998244353\) 取模。多组数据。

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int M=998244353,inv2=499122177,inv6=166374059;
struct node{ll f,g,h;};
inline ll sq(ll x){x%=M;return x*x%M;}
inline ll s2(ll x){x%=M;return x*(x+1)%M*inv2%M;}
inline ll s3(ll x){x%=M;return x*(x+1)%M*(2*x+1)%M*inv6%M;}
node calc(ll a,ll b,ll c,ll n){
	if(!a) return node{(n+1)*(b/c)%M,(n+1)*sq(b/c)%M,s2(n)*(b/c)%M};
	if(a<c&&b<c){
		ll m=(a*n+b)/c;
		if(!m) return node{0ll,0ll,0ll};
		node t=calc(c,c-b-1,a,m-1),s;m%=M;
		s.f=(m*n%M+M-t.f)%M;
		s.g=((2*s2(m)*n%M-2*t.h-2*t.f-s.f)%M+M)%M;
		s.h=((2*s2(n)*m%M-t.f-t.g)%M+M)%M*inv2%M;
		return s;
	}
	else{
		node t=calc(a%c,b%c,c,n),s;
		s.f=(t.f+s2(n)*(a/c)%M+(n+1)*(b/c)%M)%M;
		s.g=(t.g+sq(a/c)*s3(n)%M+(n+1)*sq(b/c)%M+2*(a/c)*t.h%M+2*(b/c)*t.f%M+2*(a/c)*(b/c)%M*s2(n)%M)%M;
		s.h=(t.h+(a/c)*s3(n)%M+(b/c)*s2(n)%M)%M;
		return s;
	}
}
signed main(){
	int t,n,a,b,c;
	cin>>t;
	while(t--){
		cin>>n>>a>>b>>c;
		node ans=calc(a,b,c,n);
		cout<<ans.f<<" "<<ans.g<<" "<<ans.h<<"\n";
	}
	return 0;
}

二次剩余(贺的):

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct num {
	ll x,y;
};

ll t,w,n,p;

num mul(num a,num b,ll p) {
	num res;
	res.x=( (a.x*b.x%p+a.y*b.y%p*w%p) %p+p)%p;
	res.y=( (a.x*b.y%p+a.y*b.x%p) %p+p)%p;
	return res;
}
ll ksmr(ll a,ll b,ll p) {// 实数快速幂 
	ll res=1;
	while(b) {
		if(b&1) res=res*a%p;
		a=a*a%p;
		b>>=1;
	}
	return res;
}
ll ksmi(num a,ll b,ll p){
	num res={1,0};
	while(b){
		if(b&1) res=mul(res,a,p);
		a=mul(a,a,p);
		b>>=1;
	}
	return res.x%p; 
}
ll cipolla(ll n,ll p){
	n%=p;
	if(ksmr(n,(p-1)/2,p)==-1+p) return -1;
	ll a;
	while(1) {
		a=rand()%p;
		w=(((a*a)%p-n)%p+p)%p;
		if(ksmr(w,(p-1)/2,p)==p-1) break;
	}
	num x={a,1};
	return ksmi(x,(p+1)/2,p);
}
int main() {
	srand(time(0));
	cin>>t;
	while(t--) {
		cin>>n>>p;
		if(n==0){
			cout<<"0"<<endl;
			continue;
		}
		ll ans1=cipolla(n,p),ans2=p-ans1;
		if(ans1==-1) cout<<"Hola!"<<endl;
		else {
			if(ans1>ans2) swap(ans1,ans2);
			if(ans1==ans2) cout<<ans1<<endl;
			else cout<<ans1<<" "<<ans2<<endl;
		}
	}
	return 0;
}

Min-Max 容斥:
全集 \(U=\{a_1,a_2,a_3,...,a_n\}\)\(\min(S)=\min\limits_{a_i∈S}a_i\)\(\max(S)=\max\limits_{a_i∈S}a_i\),有:

\[\max(S)=\sum\limits_{T\subseteq S}(-1)^{|T|+1}\min(T) \]

NTT 全家桶:

发现我并没有系统的写过任何一次全家桶,贺一个吧。

#include <stdio.h>
#define LL long long
using namespace std;

inline void jh(int &x,int &y){if(x!=y)x^=y^=x^=y;return;}

const int Rea=3e5+3;
namespace Rin
{
    char c;
    inline char gc()
    {
        static char rea[Rea];
        static char *head,*tail;
        return head==tail&&(tail=(head=rea)+fread(rea,1,Rea,stdin),head==tail)?EOF:*head++;
    }
    inline int int_()
    {
        int x=0;
        bool tag=false;
        for(c=gc();c>'9'||c<'0';c=gc())if(c=='-'){c=gc();tag=true;break;}
        for(;c>='0'&&c<='9';c=gc())x=(x<<1)+(x<<3)+(c^'0');
        if(tag)x=-x;
        return x;
    }
}
const int N=3e5+3;
namespace Mod
{
    const int M=998244353;
    inline int prpr(int x,int y){return 1LL*x*y%M;}
    inline int ksm(int x,int y){int ans=1;for(;y;y>>=1){if(y&1)ans=prpr(ans,x);x=prpr(x,x);}return ans;}
}
using namespace Mod;
namespace fac
{
    int sl[N];
    int sr[N];
    inline void init()
    {
        sl[0]=sr[0]=1;
        for(int i=1;i<N;i++)sl[i]=prpr(sl[i-1],i);
        sr[N-1]=ksm(sl[N-1],M-2);for(int i=N-2;i;i--)sr[i]=prpr(sr[i+1],i+1);
        return;
    }
}
namespace dxs
{
    int Alpha[N];
    int Beta[N];
    int Zeta[N];
    const int K=3;
    const int Kr=ksm(K,M-2);
    int lens;
    int lenr;
    int num[N];
    int unit[2][23];
    inline void init_lens(int L){for(lens=1;lens<L;lens<<=1);return;}
    inline void init(int L)
    {
        int lg=0;
        for(lens=1;lens<L;lens<<=1)lg++;lenr=ksm(lens,M-2);
        for(int i=1;i<lens;i++)num[i]=((num[i>>1]>>1)|((i&1)<<lg-1));
        for(int i=1,lg=0;i<lens;i<<=1,lg++)unit[0][lg]=ksm(K,(M-1)/(i<<1)),unit[1][lg]=ksm(Kr,(M-1)/(i<<1));
        return;
    }
    inline void mem0(int *a,int L){for(int i=L;i<lens;i++)a[i]=0;return;}
    inline void abs(int *a,int L){for(int i=0;i<L;i++)a[i]=(a[i]+M)%M;return;}
    inline void copy(int *a,int *b,int L){for(int i=0;i<L;i++)b[i]=a[i];mem0(b,L);return;}
    inline void NTT(int *a,int tag)
    {
        for(int i=1;i<lens;i++)if(num[i]>i)jh(a[num[i]],a[i]);
        for(int i=1,lg=0;i<lens;i<<=1,lg++)
        {
            int Gyq=unit[tag==-1][lg];
            for(int j=0;j<lens;j+=(i<<1))
            {
                int Zjj=1;
                for(int k=0;k<i;k++,Zjj=prpr(Zjj,Gyq))
                {
                    int x=a[j+k],y=prpr(a[j+k+i],Zjj);
                    a[j+k]=(x+y)%M;
                    a[j+k+i]=(x-y)%M;
                }
            }
        }
        if(tag==-1)for(int i=0;i<lens;i++)a[i]=prpr(a[i],lenr);
        return;
    }
    inline void Inv(int *a,int *b,int L)
    {
        if(L==1){b[0]=ksm(a[0],M-2);return;}
        Inv(a,b,L+1>>1);init((L<<1)-1);copy(a,Alpha,L);mem0(Alpha,L);
        NTT(Alpha,1);NTT(b,1);for(int i=0;i<lens;i++)b[i]=prpr(b[i],2-prpr(Alpha[i],b[i]));NTT(b,-1);mem0(b,L);
        return;
    }
    inline void inv(int *a,int *b,int L){init_lens((L<<1)-1);mem0(b,0);Inv(a,b,L);return;}
    inline void der(int *a,int *b,int L){for(int i=1;i<L;i++)b[i-1]=prpr(a[i],i);mem0(b,L-1);return;}
    inline void inte(int *a,int *b,int L){using namespace fac;for(int i=1;i<L;i++)b[i]=prpr(a[i-1],prpr(sr[i],sl[i-1]));b[0]=0;mem0(b,L);return;}
    inline void ln(int *a,int *b,int L)
    {
        init((L<<1)-1);mem0(b,0);mem0(Alpha,0);
        inv(a,Beta,L);der(a,Alpha,L);
        NTT(Beta,1);NTT(Alpha,1);for(int i=0;i<lens;i++)Alpha[i]=prpr(Alpha[i],Beta[i]);NTT(Alpha,-1);
        inte(Alpha,b,L);
        return;
    }
    inline void Exp(int *a,int *b,int L)
    {
        if(L==1){b[0]=1;return;}
        Exp(a,b,L+1>>1);
        ln(b,Zeta,L);for(int i=0;i<L;i++)Zeta[i]=(a[i]-Zeta[i])%M;Zeta[0]=(Zeta[0]+1)%M;
        NTT(Zeta,1);NTT(b,1);for(int i=0;i<lens;i++)b[i]=prpr(b[i],Zeta[i]);NTT(b,-1);
        mem0(b,L);
        return;
    }
    inline void exp(int *a,int *b,int L){init_lens((L<<1)-1);mem0(b,0);Exp(a,b,L);return;}
}

int n;
int A[N];
int B[N];
inline void work()
{
    {using namespace Rin;n=int_()-1;for(int i=0;i<=n;i++)A[i]=int_();}
    {using namespace dxs;exp(A,B,n+1);abs(B,n+1);}
    for(int i=0;i<=n;i++)printf("%d ",B[i]);printf("\n");
    return;
}

int main()
{
    {using namespace fac;init();}
    work();
    return 0;
}

posted @ 2026-05-15 14:17  Xuan_tmp  阅读(22)  评论(0)    收藏  举报