省选测试38

选拔赛

  • 先给a数组和c数组从大到小排序,D[l][r]表示分配完前K个人(A组)大于等于l,后n-K个(B组)小于等于r,枚举A组的最小分数L,D[L][L]-D[L+1][L]的和即为答案,D[L][L]和D[L+1][L]直接每次用每次dp即可,总复杂度 n^4

  • 我们会发现随着c数组中数值的减小,对于A组,能匹配的人数在减小,对于B组,能匹配的人数在增多,我们可以把当前的c[i]给还未匹配的,能匹配c最少的A组人或B组人,这样预处理出c[i]能匹配的A组人数k[i],以及能匹配的B组人数z[i],再定义dp[i][j]表示前i个c,给了A组j个的方案数,就能转移了。

  • 通过讨论c[i]给A还是给B,知道这是给A/B的第几个c,也就知道转移系数(当前的c[i]的贡献)了,自己理解的不太清楚,


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
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define double long double
using namespace std;

const int maxn=30;
const double eps=1e-8;
const double pi=M_PI;

struct Node{
	double x,y;
	Node operator - (const Node &B) const {return (Node){x-B.x,y-B.y};}
	Node operator + (const Node &B) const {return (Node){x+B.x,y+B.y};}
	Node operator * (const double &B) const {return (Node){x*B,y*B};}
	double operator ^ (const Node &B) const {return x*B.y-B.x*y;};
	double operator ~ () const {return sqrt(x*x+y*y);}
	bool operator < (const Node &B) const {
		double at1=atan2(y,x),at2=atan2(B.y,B.x);
		return at1!=at2?at1<at2:x<B.x;
	}
};
struct Line{
	Node st,ed;
	bool operator & (const Line &B) const {//跨立实验,判线段相交
		return ((B.ed-st)^(ed-st))*((B.st-st)^(ed-st))<0&&((ed-B.st)^(B.ed-B.st))*((st-B.st)^(B.ed-B.st))<0;
	}
	Node operator * (const Line &B) const {//线段交点
		Node x=ed-st,y=B.ed-B.st,z=B.st-st;
		return st+x*((y^z)/(y^x));
	}
};
struct Sim{
	Node x;
	bool opt;
	bool operator < (const Sim &B) const {return x<B.x;}
};
vector <Sim> vec;

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;
}

int main(){
	freopen("cut.in","r",stdin);
	freopen("cut.out","w",stdout);
	int n=read(),R=read(),top=2; vec.resize(3);
	vec[1]=(Sim){(Node){-1.0l*R,0},1};
	vec[0]=vec[2]=(Sim){(Node){1.0l*R,0},1};
	Node O=(Node){0,0};
	while(n-->0){
		double ang=read()*pi/180,h; scanf("%LF",&h);
		if(fabs(h-R)<=eps) continue;
		Node s=(Node){cos(ang-acos(h/R))*R,sin(ang-acos(h/R))*R};//和圆的一交点
		Node t=(Node){cos(ang+acos(h/R))*R,sin(ang+acos(h/R))*R};//和圆的另一交点
		Node tmp1,tmp2;int p1=0,p2=0;
		for(int i=1;i<=top;++i){
			if(vec[i].opt){
				if(((s-vec[i-1].x)^(vec[i].x-vec[i-1].x))>0){
					if(!p1) p1=i,tmp1=s;
					else p2=i,tmp2=s;
				}
				if(((t-vec[i-1].x)^(vec[i].x-vec[i-1].x))>0){
					if(!p1) p1=i,tmp1=t;
					else p2=i,tmp2=t;
				}
			}
			else if((Line){vec[i-1].x,vec[i].x}&(Line){s,t}){
				if(!p1) p1=i,tmp1=(Line){vec[i-1].x,vec[i].x}*(Line){s,t};
				else p2=i,tmp2=(Line){vec[i-1].x,vec[i].x}*(Line){s,t};
			}
		}
		if(!p2) continue;
		if(((O-tmp1)^(tmp2-tmp1))<0){
			bool opt=vec[p1].opt;
			top-=p2-p1;
			for(int i=p2-1;i>=p1;--i) vec.erase(vec.begin()+i);
			vec.push_back((Sim){tmp1,opt});
			vec.push_back((Sim){tmp2,0});
			top+=2;
		}
		else{
			bool opt=vec[p2].opt;
			for(int i=top;i>=p2;--i) vec.erase(vec.begin()+i);
			for(int i=p1-1;i>=1;--i) vec.erase(vec.begin()+i);
			top=p2-p1;
			vec.push_back((Sim){tmp1,0});
			vec.push_back((Sim){tmp2,opt});
			top+=2;
		}
		sort(vec.begin()+1,vec.begin()+top+1),vec[0]=vec[top];
	}
	double ans1=0,ans2=0;
	for(int i=1;i<=top;++i){
		if(vec[i].opt){
			double tmp=atan2(vec[i].x.y,vec[i].x.x)-atan2(vec[i-1].x.y,vec[i-1].x.x);
			if(tmp<0) tmp+=2*pi;
			ans2+=tmp*R;
		}
		else ans1+=(~(vec[i].x-vec[i-1].x));
	}
	printf("%.10LF %.10LF\n",ans1,ans2);
	return 0;
}
posted @ 2021-03-15 19:56  liuzhaoxu  阅读(37)  评论(0编辑  收藏  举报