省选模拟41

A. 环

先将 \(a_i\) 从小到大排序

考虑 \(dp\) ,设 \(f_{i,j}\) 表示考虑左边前 \(i\) 个点,右边前 \(a_i\) 个点,有 \(j\) 个链的方案数

这里把单点也当成是链,同时给链定向

转移时分别考虑新加进来几个点,是否合并两个链

新加点进来时要乘上组合数系数

在合并链之前判断能否连成环,因为 \(a_i\) 单调不降所以转移很简单

Code
#include<bits/stdc++.h>
#define int long long//MEM LIM OVER FLOW
#define meow(args...) fprintf(stderr,args)
#define mod 998244353
#define i2 499122177
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,ans;
int a[5010];
int f[5010][5010],fac[5010],inv[5010];
inline int C(int n,int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=res*base%mod;base=base*base%mod;k>>=1;}
	return res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("ring.in","r",stdin);
	freopen("ring.out","w",stdout);
	fac[0]=inv[0]=1;for(int i=1;i<=5000;i++) fac[i]=fac[i-1]*i%mod,inv[i]=inv[i-1]*qpow(i,mod-2)%mod;
	n=read();for(int i=1;i<=n;i++) a[i]=read();sort(a+1,a+1+n);f[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=a[i];j++) for(int k=0;k<=a[i]-a[i-1];k++) if(j-k>=0) f[i][j]+=f[i-1][j-k]*C(a[i]-a[i-1],k);
		(ans+=f[i][1]-a[i]+mod)%=mod;
		for(int j=0;j<=a[i];j++) (f[i][j]+=f[i][j+1]*j%mod*(j+1)%mod)%=mod;
	}
	printf("%lld\n",ans*i2%mod);
	return 0;
}

B. 数

答案的形式是 \(4p,16p,[p\% 4=3]\) 其中 \(p\) 为任意奇质数

\(Min\_25\) 筛分别记录质数个数和 \(\%4=3\)\(\%4=1\) 的值

Code
#include<bits/stdc++.h>
#define int long long//MEM LIM OVER FLOW
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,sqn,v1,v2;
int ind1[1000010],ind2[1000010],w[1000010],tot;
int prime[1000010],s1[1000010],s2[1000010],g1[1000010],g2[1000010],f[1000010],cnt;
bool is[1000010];
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("number.in","r",stdin);
	freopen("number.out","w",stdout);
	n=read();sqn=sqrt(n);
	for(int i=2;i<=sqn;i++){
		if(!is[i]){
			prime[++cnt]=i;
			s1[cnt]=s1[cnt-1]+(i%4==1);
			s2[cnt]=s2[cnt-1]+(i%4==3);
		}
		for(int j=1;j<=cnt&&i*prime[j]<=sqn;j++){
			is[i*prime[j]]=1;
			if(i%prime[j]==0) break;
		}
	}
	for(int l=1,r;l<=n;l=r+1){
		r=n/(n/l);w[++tot]=n/l;
		f[tot]=w[tot]-1;
		g1[tot]=(w[tot]-1)/4;
		g2[tot]=(w[tot]+1)/4;
		if(n/l<=sqn) ind1[n/l]=tot;else ind2[n/(n/l)]=tot;
	}
	for(int i=1;i<=cnt;i++){
		for(int j=1,k;j<=tot&&prime[i]*prime[i]<=w[j];j++){
			k=w[j]/prime[i]<=sqn?ind1[w[j]/prime[i]]:ind2[n/(w[j]/prime[i])];
			f[j]-=(f[k]-(i-1));
			if(prime[i]%4==1){
				g1[j]-=(g1[k]-s1[i-1]);
				g2[j]-=(g2[k]-s2[i-1]);
			}
			if(prime[i]%4==3){
				g1[j]-=(g2[k]-s2[i-1]);
				g2[j]-=(g1[k]-s1[i-1]);
			}
		}
	}
	v1=n/4; if(v1<=sqn) v1=ind1[v1];else v1=ind2[n/v1];
	v2=n/16;if(v2<=sqn) v2=ind1[v2];else v2=ind2[n/v2];
	printf("%lld\n",g2[1]+f[v1]+f[v2]);
	return 0;
}

C. 矩阵

考虑用扫描线做

询问离线下来后分治做,把询问拆成 \([l,mid]\)\([mid+1,r]\)

再从左边和右边分别扫一遍处理询问

剩下的可以用线段树区间历史最值来维护

每扫到一个分治中心就清一遍最值

清空最值可以让整颗树都加上一个很大的值,让历史最值变成这个数,就相当于清空了,然后查询时再减去这个数

Code
#include<bits/stdc++.h>
#define int long long//MEM LIM OVER FLOW
#define meow(args...) fprintf(stderr,args)
#define inf 0x3f3f3f3f3f3f3f3f
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,q,V,C,T;
int ans[200010],k2[50];
struct U{int l,r,k;};
struct Q{int l,r,id;};
vector<U>v1[65536],v2[65536];
vector<Q>vl[65536][16],vr[65536][16],vec[65536];
struct seg{int mx,atag,hmx,hatag,ctag;}st[50010*4];
inline void pushup(int rt){
	st[rt].mx=max(st[lson].mx,st[rson].mx);
	st[rt].hmx=max(st[lson].hmx,st[rson].hmx);
}
inline void pushdown(int rt){
	if(st[rt].atag||st[rt].hatag){
		st[lson].hmx=max(st[lson].hmx,st[lson].mx+st[rt].hatag);
		st[rson].hmx=max(st[rson].hmx,st[rson].mx+st[rt].hatag);
		st[lson].hatag=max(st[lson].hatag,st[lson].atag+st[rt].hatag);
		st[rson].hatag=max(st[rson].hatag,st[rson].atag+st[rt].hatag);
		st[lson].atag+=st[rt].atag;st[lson].mx+=st[rt].atag;
		st[rson].atag+=st[rt].atag;st[rson].mx+=st[rt].atag;
		st[rt].atag=0,st[rt].hatag=0;
	}
}
void upd(int rt,int l,int r,int L,int R,int k){
	if(L<=l&&r<=R) return st[rt].hatag=max(st[rt].hatag,st[rt].atag+k),st[rt].hmx=max(st[rt].hmx,st[rt].mx+k),st[rt].mx+=k,st[rt].atag+=k,void();
	int mid=(l+r)>>1;pushdown(rt);
	if(L<=mid) upd(lson,l,mid,L,R,k);
	if(R>mid) upd(rson,mid+1,r,L,R,k);
	pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
	if(L<=l&&r<=R) return st[rt].hmx;
	int mid=(l+r)>>1,res=0;pushdown(rt);
	if(L<=mid) res=max(res,query(lson,l,mid,L,R));
	if(R>mid) res=max(res,query(rson,mid+1,r,L,R));
	return res;
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	k2[0]=1;for(int i=1;i<=20;i++) k2[i]=k2[i-1]*2;
	n=read(),m=read(),q=read();for(int i=0;i<16;i++) if((n>>i)&1) V=i;
	for(int i=1,x,xx,y,yy,k;i<=m;i++){
		x=read(),y=read(),xx=read(),yy=read(),k=read();
		v1[x].emplace_back((U){y,yy,k});v1[xx+1].emplace_back((U){y,yy,-k});
		v2[xx].emplace_back((U){y,yy,k});v2[x-1].emplace_back((U){y,yy,-k});
	}
	for(int i=1,x,xx,y,yy,mid;i<=q;i++){
		x=read(),y=read(),xx=read(),yy=read();mid=1<<V;
		if(x==xx){vec[x].emplace_back((Q){y,yy,i});continue;}
		if(x+1==xx){vec[x].emplace_back((Q){y,yy,i});vec[xx].emplace_back((Q){y,yy,i});continue;}
		for(int v=V;~v;v--){
			if(x<=mid&&xx>mid){
				vl[x ][v-1].emplace_back((Q){y,yy,i});
				vr[xx][v-1].emplace_back((Q){y,yy,i});
				break;
			}
			if(xx<=mid) mid-=1<<(v-1);
			else mid+=1<<(v-1);
		}
	}
	memset(st,0,sizeof(st));
	for(int i=1;i<=n;i++){
		for(auto L:v1[i]) if(L.k<0) upd(1,1,n,L.l,L.r,L.k);
		for(auto L:v1[i]) if(L.k>0) upd(1,1,n,L.l,L.r,L.k);
		T=st[1].hmx;upd(1,1,n,1,n,st[1].hmx-C);C+=T-C;
		for(auto L:vec[i]) ans[L.id]=max(ans[L.id],query(1,1,n,L.l,L.r)-C);
	}
	for(int v=0;v<=V;v++){
		memset(st,0,sizeof(st));C=0;
		for(int i=1;i<=n;i++){
			for(auto L:v1[i]) if(L.k<0) upd(1,1,n,L.l,L.r,L.k);
			for(auto L:v1[i]) if(L.k>0) upd(1,1,n,L.l,L.r,L.k);
			for(auto L:vr[i][v]) ans[L.id]=max(ans[L.id],query(1,1,n,L.l,L.r)-C);
			if(i%k2[v+1]==0){T=st[1].hmx;upd(1,1,n,1,n,st[1].hmx-C);C+=T-C;}
		}
		memset(st,0,sizeof(st));C=0;
		for(int i=n;i>=1;i--){
			if(i%k2[v+1]==0){T=st[1].hmx;upd(1,1,n,1,n,st[1].hmx-C);C+=T-C;}
			for(auto L:v2[i]) if(L.k<0) upd(1,1,n,L.l,L.r,L.k);
			for(auto L:v2[i]) if(L.k>0) upd(1,1,n,L.l,L.r,L.k);
			for(auto L:vl[i][v]) ans[L.id]=max(ans[L.id],query(1,1,n,L.l,L.r)-C);
		}
	}
	for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2022-03-31 21:39  Max_QAQ  阅读(45)  评论(0编辑  收藏  举报