• ! AHOI/HNOI2017大佬


    利用不等式解题,搜索剪枝



    SOL:

    首先可以发现保证自己不死和怼大佬是可以分开的

    一个(n^2DP)算出最多可以用来怼大佬的天数,问题就转化为用(n)天怼大佬是否成功

    先求出所有可能的讽刺值及其天数,惊人发现竟存的下!看来要多尝试才好

    这样攻击一次和零次的都可以轻易判断

    攻击两次(讽刺值(f1,f2)天数(d1,d2)):

    (f1+f2<=C,n-d1-d2>=C-f1-f2)

    可以排序后,用一个指针记录第二次攻击进行到哪了(根据第一个式子,单调性)

    ((f1-d1)+(f2-d2)>=C-n)

    记录(f2-d2)的最大值即可

    注:

    搜索时判重,若同一层出现了一样的值则无效

    按理说讽刺值一样是应是保留天数少的,但(L)不一定一样,我们必须让它搜下去,若直接搜要爆掉

    这样判可以保证数的构造唯一,(L)唯一,不会漏,也不多

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	int x=0,f=1;char c=getchar();
    	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
    	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    	return f==1?x:-x;
    }
    #define ll long long
    unordered_map<ll,bool>mp;
    pair<int,int>dam[1111111];
    #define fi(i) dam[i].first
    #define se(i) dam[i].second 
    struct node{int i,f,l;};
    const int N=304;
    int n,m,day,tot,mx,mc;
    int a[N],w[N],c[N],g[N][N];
    void bfs(){
    	queue<node>q;
    	q.push((node){1,1,0});
    	while(!q.empty()){
    		node u=q.front();q.pop();
    		if(u.i==day)continue;
    		q.push((node){u.i+1,u.f,u.l+1});
    		if(u.l>1&&(ll)u.f*u.l<=mx&&!mp[(ll)u.f*u.l*100+u.i+1]){
    			q.push((node){u.i+1,u.f*u.l,u.l});
    			dam[++tot]=make_pair(u.f*u.l,u.i+1);
    			mp[(ll)u.f*u.l*100+u.i+1]=1;
    		}
    	}
    }
    int main(){
    	n=read();m=read();mc=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<=n;i++)w[i]=read();
    	for(int i=1;i<=m;i++)mx=max(mx,c[i]=read());
    	for(int i=1;i<=n;i++)
    		for(int j=a[i];j<=mc;j++){
    			g[i][j-a[i]]=max(g[i][j-a[i]],g[i-1][j]+1);
    			g[i][min(mc,j-a[i]+w[i])]=max(g[i][min(mc,j-a[i]+w[i])],g[i-1][j]);
    		}
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=mc;j++)day=max(day,g[i][j]);
    	bfs();
    	sort(dam+1,dam+tot+1);
    	for(int i=1,fl,mn;i<=m;i++){
    		if(c[i]<=day){puts("1");continue;}
    		fl=0;mn=1e9;
    		for(int j=tot,k=1;j;j--){
    			while(k<=tot&&fi(j)+fi(k)<=c[i]){
    				mn=min(mn,se(k)-fi(k));
    				++k;
    			}
    			if(mn+c[i]-fi(j)<=day-se(j)){fl=1;break;}
    			if(fi(j)<=c[i]&&c[i]-fi(j)<=day-se(j)){fl=1;break;}
    		}
    		if(fl==1)puts("1");
    		else puts("0");
    	}
    	return (0-0);
    }
    
  • 相关阅读:
    Python闭包
    使用python在极坐标中生成一条直线
    使用python生成c文件模板
    使用python转换markdown to html
    使用python转换编码格式
    安装PyQt5和Eric6
    2.深入剖析地址转化
    1.MMU功能解析
    37.C与汇编混合编程
    36.从汇编到C(bl1到bl2)
  • 原文地址:https://www.cnblogs.com/aurora2004/p/12523939.html
Copyright © 2020-2023  润新知