• 【校内模拟】神光


    看到(“L 的最小值”),很容易想到二分答案,那么这道题的关键就是如何快速地检验

    首先,如果已经规定了操作顺序,我们可以(O(n))贪心求解

    但是要枚举顺序的话复杂度是阶乘级别的,显然布星

    于是考虑(DP),我一开始的(DP)状态:(dp[i][j])表示干掉前(i)(fa)坛,用(j)次红光时的最少用多少次绿光

    发现转移有些麻烦,又因为时间不大够了,我就随机操作顺序+贪心(100)次了(骗到(60)分)

    题解的做法:

    (dp[i][j]表示用i次color{green}{绿光}和j次color{red}{红光}最多摧毁从1开始多少个连续的法坛)

    转移就是

    [dp[i][j]=P[dp[i-1][j]+1]+Q[dp[i][j-1]+1] ]

    其中(P[k])表示从第(k)个法坛开始向右(L)长度内有多少法坛,(Q[k])表示从第(k)个法坛开始向右(2L)长度内有多少法坛,都可以在(DP)前预处理出来

    (60)分随机算法:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<cstdio>
    #include<ctime>
    using namespace std;
    const int N=2010;
    int n,r,g,a[N];
    inline bool check(int l){
    	int t=100;
    	while(t--){
    		int tot1=0,tot2=0,dr=0;
    		for(int i=1;i<=n;i++){
    			if(a[i]<dr) continue;
    			if((rand()%2||tot2==g)&&tot1!=r){
    				dr=a[i]+l-1; ++tot1;
    				if(dr>a[n]) return 1;
    			}
    			else if(tot2!=g){
    				dr=a[i]+l+l-1; ++tot2;
    				if(dr>a[n]) return 1;
    			}
    			else break;
    		}
    		if(dr>a[n]) return 1;
    	}
    	return 0;
    }
    int main()
    {
    	srand(19260817+time(NULL));
    	freopen("light.in","r",stdin);
    	freopen("light.out","w",stdout);
    	scanf("%d%d%d",&n,&r,&g);
    	if(r+g>=n){
    		puts("1");
    		return 0;
    	}
    	for(int i=1;i<=n;++i)
    		scanf("%d",&a[i]);
    	sort(a+1,a+1+n);
    	int l=1,r=1000000000;
    	while(l<r){
    		int mid=(l+r)>>1;
    		if(check(mid)) r=mid;
    		else l=mid+1;
    	}
    	printf("%d
    ",l);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    

    (100)分代码

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define N 2010
    #define reset(a) memset(a,0,sizeof(a))
    int n,r,g,a[N],dp[N][N];
    int P[N],Q[N];
    bool check(int L)
    {
    	reset(P),reset(Q),reset(dp);
    	for(int i=1;i<=n;i++){
    		int j=i;
    		while(a[j]<=a[i]+L-1&&j<=n) ++j;
    		P[i]=j-1;
    		while(a[j]<=a[i]+L+L-1&&j<=n) ++j;
    		Q[i]=j-1;
    	}
    	P[n+1]=Q[n+1]=n;
    	for(int i=0;i<=r;i++)
    	 for(int j=0;j<=g;j++){
    	    if(i) dp[i][j]=max(dp[i][j],P[dp[i-1][j]+1]);
    	    if(j) dp[i][j]=max(dp[i][j],Q[dp[i][j-1]+1]);
    	}
    	return dp[r][g]==n;
    }
    int main()
    {
    	freopen("light.in","r",stdin);
    	freopen("light.out","w",stdout);
    	scanf("%d%d%d",&n,&r,&g);
    	if(r+g>=n){
    		puts("1");
    		return 0;
    	}
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	sort(a+1,a+1+n);
    	int l=1,r=1e9;
    	while(l<r){
    		int mid=(l+r)>>1;
    		if(check(mid)) r=mid;
    		else l=mid+1;
    	}
    	printf("%d
    ",l);
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    [ZOJ 3622] Magic Number
    SGU 134.Centroid(图心)
    SGU 223.Little Kings
    C++ IO 详细用法
    POJ2632 Crashing Robots 解题报告
    POJ1068 Parencodings 解题报告
    POJ3295 Tautology 解题报告
    POJ2586 Y2K Accounting Bug 解题报告
    POJ1328 Radar Installation 解题报告
    POJ3728 The merchant解题报告
  • 原文地址:https://www.cnblogs.com/yjkhhh/p/9799915.html
Copyright © 2020-2023  润新知