其他分享
首页 > 其他分享> > 省选测试38

省选测试38

作者:互联网

选拔赛


Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;

const int mod=1e9+7;
int n,K,tc,ans;
int a[105],c[105],T[10005],k[105],z[105],f[105][105];

int D(int L,int R){
	memset(k,0,sizeof k);
	memset(z,0,sizeof z);
	for(int i=1;i<=n;++i){
		for(int j=1;j<=K;++j) if(c[i]+a[j]>=L) ++k[i]; else break;
		for(int j=n;j>=K+1;--j) if(c[i]+a[j]<=R) ++z[i]; else break;
	}
	f[0][0]=1;
	for(int i=1;i<=n;++i){
		for(int j=0;j<=i&&j<=K;++j){
			int A=j,B=i-j;
			f[i][j]=0;
			if(A&&k[i]>K-A) (f[i][j]+=(ll)f[i-1][j-1]*(k[i]-(K-A))%mod)%=mod;
			if(B&&z[i]>B-1) (f[i][j]+=(ll)f[i-1][j]*(z[i]-(B-1))%mod)%=mod;
		}
	}
	return f[n][K];
}

int main(){
	freopen("select.in","r",stdin);
	freopen("select.out","w",stdout);
	scanf("%d%d",&n,&K);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
	for(int i=1;i<=n;++i) scanf("%d",&c[i]);
	sort(a+1,a+1+n,greater<int>());
	sort(c+1,c+1+n,greater<int>());
	for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) T[++tc]=a[i]+c[j];
	sort(T+1,T+1+tc);
	tc=unique(T+1,T+1+tc)-(T+1);
	for(int i=1;i<=tc;++i) (ans+=D(T[i],T[i])-D(T[i]+1,T[i]))%=mod;
	printf("%d\n",(ans%mod+mod)%mod);
	return 0;
}

跳跃

类似于ST表的预处理,lef[i][j]表示 i 跳 2^j 步能到达的左边界,rig[i][j]同理

\(lef[i][j]=min_{lef[i][j-1] \leq x \leq rig[i][j-1]} lef[x][j-1];\)

\(rig[i][j]=max_{lef[i][j-1] \leq x \leq rig[i][j-1]} rig[x][j-1];\)

预处理的时候因为要查询区间min,max所以要用ST表,其实后面倍增的时候也要查询,所以这个ST表多开一维,后面再用就不要需要预处理了,

倍增就是类似于倍增lca跳父亲,枚举当前二进制位,看答案能否加上,如果答案加上该2的次幂,仍存在两个点相互到达不了的,那么就加上,最后输出ans+1即可,这样不用二分,二分的话总复杂度 \(O(nlog^2+nlog^2)\) ,这样倍增的话优秀一点,复杂度 \(O(nlog^2+nlog)\)

Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int maxn=2e5+10;
int n,ans,lg[maxn];
int Max[maxn],lal[maxn],lar[maxn],vl[maxn],vr[maxn],lef[20][maxn],rig[20][maxn];
int mn[20][20][maxn],mx[20][20][maxn];

int read(int x=0,bool f=0,char ch=getchar()){
	for(;ch<'0' || ch>'9';ch=getchar()) f=ch=='-';
	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch&15);
	return f?-x:x;
}

void Pre(int d){
	for(int i=1;i<=lg[n];++i){
		for(int j=1;j+(1<<i)-1<=n;++j){
			mn[d][i][j]=min(mn[d][i-1][j],mn[d][i-1][j+(1<<(i-1))]);
			mx[d][i][j]=max(mx[d][i-1][j],mx[d][i-1][j+(1<<(i-1))]);
		}
	}
}

int askmin(int x,int l,int r){
	int d=lg[r-l+1];
	return min(mn[x][d][l],mn[x][d][r+1-(1<<d)]);
}

int askmax(int x,int l,int r){
	int d=lg[r-l+1];
	return max(mx[x][d][l],mx[x][d][r+1-(1<<d)]);
}

int main(){
	freopen("jump.in","r",stdin);
	freopen("jump.out","w",stdout);
	n=read();
	for(int i=2;i<=n;++i) lg[i]=lg[i/2]+1;
	for(int i=1;i<=n;++i){
		int x=read();
		mn[0][0][i]=lef[0][i]=max(1,i-x);
		mx[0][0][i]=rig[0][i]=min(n,i+x);
	}
	for(int d=1;d<=lg[n];++d){
		Pre(d-1);
		for(int i=1;i<=n;++i){
			mn[d][0][i]=lef[d][i]=askmin(d-1,lef[d-1][i],rig[d-1][i]);
			mx[d][0][i]=rig[d][i]=askmax(d-1,lef[d-1][i],rig[d-1][i]);
		}
	}
	Pre(lg[n]);
	Max[n+1]=1;
	for(int i=1;i<=n;++i) lal[i]=lar[i]=i;
	for(int i=lg[n];i>=0;--i){
		for(int x=1;x<=n;++x){
			vl[x]=askmin(i,lal[x],lar[x]);
			vr[x]=askmax(i,lal[x],lar[x]);
		}
		for(int x=n;x>=1;--x) Max[x]=max(Max[x+1],vl[x]);
		bool Add=0;
		for(int x=1;x<=n;++x) if(vr[x]<n&&Max[vr[x]+1]>x){Add=1;break;}
		if(Add){
			ans|=(1<<i);
			for(int x=1;x<=n;++x) lal[x]=vl[x],lar[x]=vr[x];
		}
	}
	printf("%d\n",ans+1);
	return 0;
}

切蛋糕

计算几何直接算

Code

标签:38,20,lef,省选,int,ch,maxn,测试,include
来源: https://www.cnblogs.com/Lour688/p/14539184.html