zoukankan      html  css  js  c++  java
  • 省选测试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
    ",(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
    ",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
    ",ans1,ans2);
    	return 0;
    }
    
  • 相关阅读:
    ios后台运行
    关于CRM2011插件注册更改记录状态的消息
    Microsoft Dynamics CRM 4.0字段审核跟踪功能
    CRM2011CTI集成项目
    win7下VS2010、IIS7配置常见问题收集
    CRM2011共享记录、更改状态、分派记录
    转载 [Dynamics CRM]錯誤代碼參考
    准备开发CRM2011的重要前提
    Aspx引用RDL
    CRM2011开发小技巧
  • 原文地址:https://www.cnblogs.com/Lour688/p/14539184.html
Copyright © 2011-2022 走看看