【2020省选模拟】题解

T1:

只考虑 r 1 ≤ r 2 r1\le r2 r1r2的,另外反过来做即可
考虑四种情况
1 : 1: 1:左下右
显然是 ( r 2 − r 1 ) + ( c ≠ 0 ) + c 2 (r2-r1)+(c\not=0)+c2 (r2r1)+(c=0)+c2

2 : 2: 2:下(右)左
r 2 r2 r2处处理
维护一个单调递增的栈
找到 r 1 r1 r1后第一个栈内元素 p p p
c h e m n ( c 1 , a p ) chemn(c1,a_p) chemn(c1,ap)
如果不向右靠直接下去
就是 ( r 2 − r 1 ) + ( c 2 − c 1 ) (r2-r1)+(c2-c1) (r2r1)+(c2c1)
否则是 ( r 2 − r 1 ) + min ⁡ k ( ∣ a k − c 2 ∣ ) (r2-r1)+\min_k(|a_k-c2|) (r2r1)+mink(akc2)
在栈内二分找到可能作为答案的 k k k计算即可

3 : 3: 3:上(右)下
同样在 c 2 c2 c2处理
二分找到第一个 ≤ r 1 \le r1 r1的位置
那么就是这前面的一段
对于 a p ≤ c 2 a_p\le c2 apc2
贡献是 r 1 + r 2 − 2 p + c 2 − a p r1+r2-2p+c2-a_p r1+r22p+c2ap直接找第一个 a p < c 2 a_p<c2 ap<c2就是了
否则贡献是 r 1 + r 2 − 2 p + a p − c 2 + ( c 1 > a p ) r1+r2-2p+a_p-c2+(c1>a_p) r1+r22p+apc2+(c1>ap)
对于 c 1 ≤ a p c1\le a_p c1ap c 1 > a p c1>a_p c1>ap分别计算,都是一段区间
线段树维护 a p − 2 p a_p-2p ap2p的最小值

4 : 4: 4:下(右)上
首先 c 1 c1 c1可能会在 [ r 1 , r 2 ] [r1,r2] [r1,r2]变小, c h e m n chemn chemn个区间最小值
从后往前维护一个递增栈
然后讨论类似 3 3 3
这个反着做一次即可

复杂度 O ( ( n + q ) l o g n ) O((n+q)logn) O((n+q)logn)

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define y1 shinkle
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	s[top+1]='\0';return top;
}
template<typename tp>inline void chemx(tp &a,tp b){a=max(a,b);}
template<typename tp>inline void chemn(tp &a,tp b){a=min(a,b);}
cs int N=400005,INF=1061109567;
int n,a[N],q;
namespace Seg{
	cs int N=::N<<2;
	int mn[N];
	#define lc (u<<1)
	#define rc ((u<<1)|1)
	#define mid ((l+r)>>1)
	int st,des,p,k;
	void build(){
		memset(mn,127/2,sizeof(mn));
		st=des=p=k=0;
	}
	inline void pushup(int u){
		mn[u]=min(mn[lc],mn[rc]);
	}
	void update(int u,int l,int r){
		if(l==r){mn[u]=k;return;}
		if(p<=mid)update(lc,l,mid);
		else update(rc,mid+1,r);
		pushup(u);
	}
	void delet(int u,int l,int r){
		if(l==r){mn[u]=INF;return;}
		if(p<=mid)delet(lc,l,mid);
		else delet(rc,mid+1,r);
		pushup(u);
	}
	int query(int u,int l,int r){
		if(des<l||st>r||st>des)return INF;
		if(st<=l&&r<=des)return mn[u];
		if(des<=mid)return query(lc,l,mid);
		if(mid<st)return query(rc,mid+1,r);
		return min(query(lc,l,mid),query(rc,mid+1,r));
	}
	void update(int _p,int _k){p=_p,k=_k,update(1,1,n);}
	void delet(int _p){p=_p,delet(1,1,n);}
	int query(int _st,int _des){st=_st,des=_des;return query(1,1,n);}
	#undef lc
	#undef rc
	#undef mid
}
int ans[N];
struct ask{
	int r1,c1,r2,c2,id;
};
int st[20][N],lg[N];
inline void buildst(){
	for(int i=1;i<=n;i++)st[0][i]=a[i];
	for(int i=1;(1<<i)<=n;i++)
	for(int j=1;j+(1<<i)-1<=n;j++)
	st[i][j]=min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
inline int querymn(int l,int r){
	int t=lg[r-l+1];
	return min(st[t][l],st[t][r-(1<<t)+1]);
}
int stk[N],top;
vector<ask>q1[N],q2[N],q3[N];
inline int Lower(int l,int r,int k){
	int res=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(stk[mid]>=k)res=mid,r=mid-1;
		else l=mid+1;
	}return res;
}
inline int Less(int l,int r,int k){
	int res=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(stk[mid]<=k)res=mid,l=mid+1;
		else r=mid-1;
	}return res;
}
inline int Lower2(int l,int r,int k){
	int res=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(a[stk[mid]]>=k)res=mid,r=mid-1;
		else l=mid+1;
	}return res;
}
inline int Less2(int l,int r,int k){
	int res=-1;
	while(l<=r){
		int mid=(l+r)>>1;
		if(a[stk[mid]]<=k)res=mid,l=mid+1;
		else r=mid-1;
	}return res;
}
inline int calc1(int r1,int c1,int r2,int c2){
	int ps=Lower(1,top,r1);
	assert(ps!=-1);
	int p=stk[ps],res=INF;
	chemn(c1,a[p]);
	chemn(res,(r2-r1)+abs(c2-c1));
	p=Lower2(ps,top,c2);
	if(p!=-1)chemn(res,(r2-r1)+1+abs(a[stk[p]]-c2));
	p=Less2(ps,top,c2);
	if(p!=-1)chemn(res,1+(r2-r1)+abs(a[stk[p]]-c2));
	return res;
}
inline int calc2(int r1,int c1,int r2,int c2){
	int ps=Less(1,top,r1);
	if(ps==-1)return INF;
	int p=Less2(1,ps,c2),res=INF;
	if(p!=-1)chemn(res,r1+r2-2*stk[p]+c2-a[stk[p]]+(a[stk[p]]>c1));
	if(p==-1)p=0;p++;
	int pp=Less2(p,ps,c1);
	if(pp!=-1&&p<=pp)chemn(res,Seg::query(stk[p],stk[pp])+r1+r2-c2); 
	if(pp==-1)pp=p-1;pp++;
	if(pp<=ps)chemn(res,Seg::query(stk[pp],stk[ps])+r1+r2-c2+1);
	return res;
}
inline int calc3(int r1,int c1,int r2,int c2){
	int p=Less2(1,top,c2),res=INF;
	if(p!=-1)chemn(res,2*stk[p]-a[stk[p]]-r1-r2+c2+(a[stk[p]]>c1));
	if(p==-1)p=0;p++;
	int pp=Less2(p,top,c1);
	if(pp!=-1&&p<=pp)chemn(res,Seg::query(stk[pp],stk[p])-r1-r2-c2);
	if(pp==-1)pp=p-1;pp++;
	if(pp<=top)chemn(res,Seg::query(stk[top],stk[pp])-r1-r2-c2+1);
	return res;
}
inline void solve(cs vector<ask> &q){
	Seg::build(),buildst();
	top=0;
	for(ask x:q){
		q1[x.r2].pb(x);
		chemn(x.c1,querymn(x.r1,x.r2));
		q2[x.r2].pb(x);
	}
	for(int i=1;i<=n;i++){
		while(top&&a[i]<=a[stk[top]])Seg::delet(stk[top--]);
		stk[++top]=i,Seg::update(i,a[i]-2*i);
		for(cs ask &x:q1[i])
		chemn(ans[x.id],calc1(x.r1,x.c1,x.r2,x.c2)),chemn(ans[x.id],calc2(x.r1,x.c1,x.r2,x.c2));
		q1[i].clear();
	}
	top=0;Seg::build();
	for(int i=n;i;i--){
		while(top&&a[i]<=a[stk[top]])Seg::delet(stk[top--]);
		stk[++top]=i,Seg::update(i,2*i+a[i]);
		for(ask x:q2[i]){
			chemn(ans[x.id],calc3(x.r1,x.c1,x.r2,x.c2));
		}
		q2[i].clear();
	}
}
vector<ask> qr[2];
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	freopen("my.out","w",stdout);
	#endif
	n=read();
	for(int i=2;i<=n;i++)lg[i]=lg[i>>1]+1;
	for(int i=1;i<=n;i++)a[i]=read();
	q=read();
	for(int i=1;i<=q;i++){
		int r1=read(),c1=read(),r2=read(),c2=read();
		if(r1<=r2)
		qr[0].pb(ask{r1,c1,r2,c2,i});
		else qr[1].pb(ask{n-r1+1,c1,n-r2+1,c2,i});
		ans[i]=abs(r1-r2)+c2+(c1!=0);
	}
	solve(qr[0]);
	reverse(a+1,a+n+1);
	solve(qr[1]);
	for(int i=1;i<=q;i++)cout<<ans[i]<<"\n";return 0;
}

T2:

c f 528 D cf528D cf528D
直接看每个字符能不能匹配每个位置
f f t fft fft处理通配即可

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define y1 shinkle
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
inline int readstring(char *s){
	int top=0;char ch=gc();
	while(isspace(ch))ch=gc();
	while(!isspace(ch)&&ch!=EOF)s[++top]=ch,ch=gc();
	s[top+1]='\0';return top;
}
template<typename tp>inline void chemx(tp &a,tp b){a=max(a,b);}
template<typename tp>inline void chemn(tp &a,tp b){a=min(a,b);}
cs int mod=998244353;
inline int add(int a,int b){return (a+b)>=mod?(a+b-mod):(a+b);}
inline int dec(int a,int b){return (a<b)?(a-b+mod):(a-b);}
inline int mul(int a,int b){static ll r;r=(ll)a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){a=(a+b)>=mod?(a+b-mod):(a+b);}
inline void Dec(int &a,int b){a=(a<b)?(a-b+mod):(a-b);}
inline void Mul(int &a,int b){static ll r;r=(ll)a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(ll x){x%=mod;return (x<0)?x+mod:x;}
typedef vector<int> poly;
namespace Poly{

cs int C=21,M=(1<<C)|1;
int rev[M],*w[C+1];
inline void init_w(){
	int wn=ksm(3,(mod-1)/(1<<C));
	for(int i=1;i<=C;i++)w[i]=new int[(1<<(i-1))|1];
	w[C][0]=1;
	for(int i=1,l=(1<<(C-1));i<l;i++)w[C][i]=mul(w[C][i-1],wn);
	for(int i=C-1;i;i--)
	for(int j=0,l=1<<(i-1);j<l;j++)
	w[i][j]=w[i+1][j<<1];
}
inline void init_rev(int lim){
	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
}
inline void ntt(int *f,int lim,int kd){
	for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
	for(int mid=1,l=1,a0,a1;mid<lim;mid<<=1,l++)
	for(int i=0;i<lim;i+=mid<<1)
	for(int j=0;j<mid;j++)
	a0=f[i+j],a1=mul(w[l][j],f[i+j+mid]),f[i+j]=add(a0,a1),f[i+j+mid]=dec(a0,a1);
	if(kd==-1){
		reverse(f+1,f+lim);
		for(int i=0,iv=Inv(lim);i<lim;i++)Mul(f[i],iv);
	}
}
inline poly operator *(poly a,poly b){
	int deg=a.size()+b.size()-1;
	if(a.size()<=16||b.size()<=16){
		poly c(deg,0);
		for(int i=0;i<a.size();i++)
		for(int j=0;j<b.size();j++)
		Add(c[i+j],mul(a[i],b[j]));
		return c;
	}int lim=1;	while(lim<deg)lim<<=1;
	init_rev(lim);
	a.resize(lim),ntt(&a[0],lim,1);
	b.resize(lim),ntt(&b[0],lim,1);
	for(int i=0;i<lim;i++)Mul(a[i],b[i]);
	ntt(&a[0],lim,-1),a.resize(deg);
	return a;
}

}
using namespace Poly;
cs int N=500005;
int n,m,k;
char s[N],t[N];
int f[N],ss[N][4],ok[4][N];
inline int id(char x){
	if(x=='A')return 0;
	if(x=='T')return 1;
	if(x=='G')return 2;
	return 3;
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	init_w();
	n=read(),m=read(),k=read();
	readstring(s);
	readstring(t);
	for(int i=1;i<=n;i++){
		memcpy(ss[i],ss[i-1],sizeof(ss[i-1]));
		ss[i][id(s[i])]++;
	}
	for(int i=1;i<=n;i++){
		for(int t=0;t<4;t++)if(ss[min(n,i+k)][t]-ss[max(0,i-k-1)][t]>0)ok[t][i]=1;
	}	
	for(int c=0;c<4;c++){
		poly a(n+1),b(m+1);
		for(int i=1;i<=n;i++)a[i]=ok[c][i];
		for(int i=1;i<=m;i++)b[m-i+1]=(id(t[i])==c);
		a=a*b;
		for(int j=1;j<=n-m+1;j++)f[j]+=a[j+m];
	}int res=0;
	for(int j=1;j<=n-m+1;j++)res+=f[j]==m;
	cout<<res<<'\n';return 0;
}

T3:

O ( n 2 l o g ) O(n^2log) O(n2log)的做法也比较显然吧
要么交在一个点要么都在一个面,面处理一下平行的特殊情况即可

但是很难写
于是直接判是否有交点跑最大团即可
跑的飞快

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define pb push_back
#define ll long long
#define pii pair<int,int>
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res*10)+(ch^48),ch=gc();
	return f?res:-res;
}
template<typename tp>inline void chemx(tp &a,tp b){a=max(a,b);}
template<typename tp>inline void chemn(tp &a,tp b){b=min(a,b);}
typedef double db;
cs db eps=1e-8;
inline int sign(db x){return (x>eps)-(x<-eps);}
struct pt{
	db x,y,z;
	pt(db _x=0,db _y=0,db _z=0):x(_x),y(_y),z(_z){}
	friend inline pt operator +(cs pt &a,cs pt &b){
		return pt(a.x+b.x,a.y+b.y,a.z+b.z);
	}
	friend inline pt operator -(cs pt &a,cs pt &b){
		return pt(a.x-b.x,a.y-b.y,a.z-b.z);
	}
	friend inline pt operator *(cs pt &a,cs db &b){
		return pt(a.x*b,a.y*b,a.z*b);
	}
   friend inline pt operator *(cs pt &a,cs pt &b){
        return pt(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
    }
    friend inline double operator ^(pt a,pt b){
        return a.x*b.x+a.y*b.y+a.z*b.z;
    }
	friend inline bool operator <(cs pt &a,cs pt &b){
		return (sign(a.x-b.x)==0)?((sign(a.y-b.y)==0)?(sign(a.z-b.z)==-1):(sign(a.y-b.y)==-1)):(sign(a.x-b.x)==-1);
	}
	friend inline bool operator ==(cs pt &a,cs pt &b){
		return (sign(a.x-b.x)==0)&&(sign(a.y-b.y)==0)&&(sign(a.z-b.z)==0);
	}
	inline double len()cs{return (*this)^(*this);}
};
struct Pt{
	db x,y;
	Pt(db _x=0,db _y=0):x(_x),y(_y){}
	friend inline Pt operator +(cs Pt &a,cs Pt &b){
		return Pt(a.x+b.x,a.y+b.y);
	}
	friend inline Pt operator -(cs Pt &a,cs Pt &b){
		return Pt(a.x-b.x,a.y-b.y);
	}
	friend inline db operator *(cs Pt &a,cs Pt &b){
		return a.x*b.y-a.y*b.x;
	}
	friend inline Pt operator *(cs Pt &a,cs db &b){
		return Pt(a.x*b,a.y*b);
	}
	friend inline bool operator <(cs Pt &a,cs Pt &b){
		return (sign(a.x-b.x)==0)?(sign(a.y-b.y)==-1):(sign(a.x-b.x)==-1);
	}
	friend inline bool operator ==(cs Pt &a,cs Pt &b){
		return (sign(a.x-b.x)==0)&&(sign(a.y-b.y)==0);
	}
	inline double dis(){return sqrt(x*x+y*y);}
};
cs int N=2005,M=N*N/2;
struct line{
	pt s,t;
}ln[N];
inline bool Inter(cs line &a,cs line &b){
	pt R1=a.s,R2=b.s,V1=(a.t-a.s),V2=(b.t-b.s);
	if((V1*V2).len()==0)return false;
	Pt s1(a.s.x,a.s.y),t1(a.t.x,a.t.y),s2(b.s.x,b.s.y),t2(b.t.x,b.t.y);
	double v1=(s2-s1)*(t1-s1),v2=(t1-s1)*(t2-s1);
	pt is1=b.s+(b.t-b.s)*(v1/(v1+v2));
	v1=(s2-s1)*(t2-s1),v2=(t1-s2)*(t2-s2);
	pt is2=a.s+(a.t-a.s)*(v1/(v1+v2));
	return is1==is2;
}
int n,ans;
bool e[N][N];
int lk[N][N];
void dfs(int pos,int cnt,int now){
	if(now+cnt<=ans)return;
	chemx(ans,now);
	//cout<<"bg\n";
	int u=lk[pos][1],*c=lk[pos],*d=lk[pos+1];
//	cout<<pos<<" "<<cnt<<" "<<now<<'\n';
	for(int i=1;i<=cnt;i++){
		int v=c[i],nc=0;
	//	cout<<v<<'\n';
		if(e[u][v])continue;
		for(int j=1;j<i;j++)if(e[u][c[j]]&&e[v][c[j]])d[++nc]=c[j];
		for(int j=i+1;j<=cnt;j++)if(e[v][c[j]])d[++nc]=c[j];
		dfs(pos+1,nc,now+1);
	}
	//cout<<"end\n";
}
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		ln[i].s.x=read();ln[i].s.y=read();ln[i].s.z=read();
		ln[i].t.x=read();ln[i].t.y=read();ln[i].t.z=read();
	}
	for(int i=1;i<=n;i++)
	for(int j=i+1;j<=n;j++){
		if(Inter(ln[i],ln[j])){e[i][j]=e[j][i]=1;}
	}
	for(int i=1;i<=n;i++)lk[0][i]=i;
	dfs(0,n,0);cout<<ans<<'\n';
	return 0;
}

T4:

b z o j 5284 bzoj5284 bzoj5284

考虑直接 D P DP DP需要 d p   o f   d p dp\ of\ dp dp of dp
记一下当前根选不选的最大独立集
如果记成 不 选 / 选 或 不 选 不选/选或不选 /的话可以发现 不 选 ≤ 选 或 不 选 ≤ 不 选 + 1 不选\le 选或不选 \le 不选+1 +1
于是设 f [ i ] [ j ] f[i][j] f[i][j]表示 i i i个点, 不 选 不选 j j j, 选 或 不 选 选或不选 j + 1 j+1 j+1的方案数
g [ i ] [ j ] g[i][j] g[i][j] 不 选 / 选 或 不 选 不选/选或不选 /都为 j j j的方案数

如果第二维写成生成函数
转移就是
f i = ∑ j f i − j g j f_i=\sum_jf_{i-j}g_j fi=jfijgj
g i = ∑ j g j g i − j + g i − j f j x + f i − j f j x g_i=\sum_{j}g_jg_{i-j}+g_{i-j}f_jx+f_{i-j}f_jx gi=jgjgij+gijfjx+fijfjx
这个稍微想想独立集 d p dp dp就可以明白

第二维用卷积优化即可
先转成点值最后再 I D F T IDFT IDFT回去可以做到 O ( n 3 ) O(n^3) O(n3)

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define y1 shinkle
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
template<typename tp>inline void chemx(tp &a,tp b){a=max(a,b);}
template<typename tp>inline void chemn(tp &a,tp b){a=min(a,b);}
cs int mod=998244353;
inline int add(int a,int b){return (a+b)>=mod?(a+b-mod):(a+b);}
inline int dec(int a,int b){return (a<b)?(a-b+mod):(a-b);}
inline int mul(int a,int b){static ll r;r=(ll)a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){a=(a+b)>=mod?(a+b-mod):(a+b);}
inline void Dec(int &a,int b){a=(a<b)?(a-b+mod):(a-b);}
inline void Mul(int &a,int b){static ll r;r=(ll)a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(ll x){x%=mod;return (x<0)?x+mod:x;}
cs int C=9,N=521,M=(1<<C)|1;
int rev[M],*w[C+1];
inline void init_w(){
	int wn=ksm(3,(mod-1)/(1<<C));
	for(int i=1;i<=C;i++)w[i]=new int[(1<<(i-1))|1];
	w[C][0]=1;
	for(int i=1,l=(1<<(C-1));i<l;i++)w[C][i]=mul(w[C][i-1],wn);
	for(int i=C-1;i;i--)
	for(int j=0,l=1<<(i-1);j<l;j++)
	w[i][j]=w[i+1][j<<1];
}
inline void init_rev(int lim){
	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
}
inline void ntt(int *f,int lim,int kd){
	for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
	for(int mid=1,l=1,a0,a1;mid<lim;mid<<=1,l++)
	for(int i=0;i<lim;i+=mid<<1)
	for(int j=0;j<mid;j++)
	a0=f[i+j],a1=mul(w[l][j],f[i+j+mid]),f[i+j]=add(a0,a1),f[i+j+mid]=dec(a0,a1);
	if(kd==-1){
		reverse(f+1,f+lim);
		for(int i=0,iv=Inv(lim);i<lim;i++)Mul(f[i],iv);
	}
}
int n,m,lim,f[N][N],g[N][N],xf[N][N],x[N];
inline void Inc(int *f,int *a,int *b){
	for(int i=0;i<lim;i++)Add(f[i],mul(a[i],b[i]));
}
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read();
	lim=1;while(lim<n)lim<<=1;
	init_w();init_rev(lim);
	f[1][0]=1,x[1]=1;
	ntt(f[1],lim,1),ntt(x,lim,1);
	Inc(xf[1],x,f[1]);
	for(int i=2;i<=n;i++){
		for(int j=1;j<i;j++){
			Inc(f[i],f[i-j],g[j]);
			Inc(g[i],g[i-j],g[j]);
			Inc(g[i],g[i-j],xf[j]);
			Inc(g[i],f[i-j],xf[j]);
		}Inc(xf[i],x,f[i]);
	}
	for(int i=1;i<=n;i++){
		ntt(f[i],lim,-1),ntt(g[i],lim,-1);
		cout<<g[i][0]<<" ";
		for(int j=1;j<=n;j++)cout<<add(g[i][j],f[i][j-1])<<" ";puts("");
	}
}

一个优化是可以发现最中间乘了四次
g g g可以利用加起来乘了减去就只用乘 2 2 2

另外一个优化是考虑独立集和最大匹配是相对的
于是改成 d p dp dp最大匹配,而最大匹配数只有 n / 2 n/2 n/2
这样最后一维只有 n / 2 n/2 n/2的大小
在这里插入图片描述

不过最后输出需要注意一下

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pb push_back
#define pii pair<int,int>
#define ll long long
#define y1 shinkle
#define fi first
#define se second
#define bg begin
cs int RLEN=1<<20|1;
inline char gc(){
    static char ibuf[RLEN],*ib,*ob;
    (ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
    return (ib==ob)?EOF:*ib++;
}
inline int read(){
    char ch=gc();
    int res=0;bool f=1;
    while(!isdigit(ch))f^=ch=='-',ch=gc();
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    return f?res:-res;
}
template<typename tp>inline void chemx(tp &a,tp b){a=max(a,b);}
template<typename tp>inline void chemn(tp &a,tp b){a=min(a,b);}
cs int mod=998244353;
inline int add(int a,int b){return (a+b)>=mod?(a+b-mod):(a+b);}
inline int dec(int a,int b){return (a<b)?(a-b+mod):(a-b);}
inline int mul(int a,int b){static ll r;r=(ll)a*b;return (r>=mod)?(r%mod):r;}
inline void Add(int &a,int b){a=(a+b)>=mod?(a+b-mod):(a+b);}
inline void Dec(int &a,int b){a=(a<b)?(a-b+mod):(a-b);}
inline void Mul(int &a,int b){static ll r;r=(ll)a*b;a=(r>=mod)?(r%mod):r;}
inline int ksm(int a,int b,int res=1){for(;b;b>>=1,Mul(a,a))(b&1)&&(Mul(res,a),1);return res;}
inline int Inv(int x){return ksm(x,mod-2);}
inline int fix(ll x){x%=mod;return (x<0)?x+mod:x;}
cs int C=9,N=521,M=(1<<C)|1;
int rev[M],iv,*w[C+1];
inline void init_w(){
	int wn=ksm(3,(mod-1)/(1<<C));
	for(int i=1;i<=C;i++)w[i]=new int[(1<<(i-1))|1];
	w[C][0]=1;
	for(int i=1,l=(1<<(C-1));i<l;i++)w[C][i]=mul(w[C][i-1],wn);
	for(int i=C-1;i;i--)
	for(int j=0,l=1<<(i-1);j<l;j++)
	w[i][j]=w[i+1][j<<1];
}
inline void init_rev(int lim){
	for(int i=0;i<lim;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(lim>>1));
}
inline void ntt(int *f,int lim,int kd){
	for(int i=0;i<lim;i++)if(i>rev[i])swap(f[i],f[rev[i]]);
	for(int mid=1,l=1,a0,a1;mid<lim;mid<<=1,l++)
	for(int i=0;i<lim;i+=mid<<1)
	for(int j=0;j<mid;j++)
	a0=f[i+j],a1=mul(w[l][j],f[i+j+mid]),f[i+j]=add(a0,a1),f[i+j+mid]=dec(a0,a1);
	if(kd==-1){
		reverse(f+1,f+lim);
		for(int i=0;i<lim;i++)Mul(f[i],iv);
	}
}
int n,m,lim,f[N][N],g[N][N],xf[N][N],X[N];
inline void Inc(int *f,int *a,int *b){
	for(int i=0;i<lim;i++)Add(f[i],mul(a[i],b[i]));
}
ll x[N],y[N];
int main(){
	#ifdef Stargazer
	freopen("lx.in","r",stdin);
	#endif
	n=read();
	lim=1;while(lim<(n/2+1))lim<<=1;
	init_w();init_rev(lim);
	iv=Inv(lim);
	g[1][0]=1,X[1]=1;
	ntt(g[1],lim,1),ntt(X,lim,1);
	int *a,*b,*c,*d;
	for(int i=2;i<=n;i++){
		for(int j=1;j<i;j++){
			a=g[i-j],b=f[i-j],c=xf[j],d=g[j];
			for(int k=0,tp;k<lim;k++)
			tp=mul(a[k],c[k]),
			x[k]+=(ll)(a[k]+b[k])*(c[k]+d[k])%mod-tp,
			y[k]+=tp;
		}a=f[i],b=g[i];
		for(int j=0;j<lim;j++)a[j]=fix(x[j]),b[j]=fix(y[j]),x[j]=y[j]=0;
		Inc(xf[i],X,f[i]);
	}
	for(int i=1;i<=n;i++){
		ntt(f[i],lim,-1),ntt(g[i],lim,-1);
		for(int j=i;j;j--)cout<<add(g[i][j],f[i][j-1])<<" ";
		cout<<g[i][0]<<" ";
		for(int j=i+1;j<=n;j++)cout<<0<<" ";
		puts("");
	}
}

另外:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值