• [AH2017/HNOI2017] 大佬


    大佬每天给出的伤害是固有的,设dp[i,j]表述使得前i天结束时我的自信为j最少做水题的天数。D=max(i-dp[i,j])就是总共拿来给伤害的最大天数。打伤害一类是固定的伤害1,一类是积累伤害打出(最多用两次)。不妨暴力搜索积累伤害的情形c(d,f),即我们用了d天积累了f的伤害。

    若D>=hp每次伤害1就好了(直接判);
    若存在c使得f<=hp且f+D-d>=hp,这样累计一次大佬就好了(扫一遍);
    若存在c1c1使得f1+f2<=hp且d1+d2<=D且f1+f2+D-d1-d2>=hp,这样累计两次大佬就好了;先枚举c1(d1,f1),则c2满足d2<=D-d1,f2<=hp-f1,同时也应最大化f2-d2以最大化总伤害。

    噫要是没有d2<=D-d1的限制,我们可以把所有的c按照f排序,然后决策单调性.jpg(反过来的)就非常好做了。然后就可以发现若d1+d2>D,因为f1+f2<=hp,则f1+f2+D-d1-d2<hp不可能构成解。一语成谶

    #include <bits/stdc++.h>
    #define fr first
    #define sc second
    #define ll long long 
    using namespace std;
    
    const int N=1e2+10;
    const int M=3e6+10;
    const int inf=0x3f3f3f3f;
    
    int n,m,mc,tot,a[N],w[N];
    int D,C[N],MAXC,dp[N][N];
    
    struct {
    	int cnt,head[M];
    	struct kNode{int x,y,lst;} nd[M+1];
    	void insert(int x,int y) {
    		int t=(100LL*x+y)%M;
    		nd[++cnt]=(kNode){x,y,head[t]},head[t]=cnt;
    	}
    	bool find(int x,int y) {
    		int t=(100LL*x+y)%M;
    		for(int i=head[t]; i; i=nd[i].lst) 
    			if(x==nd[i].x&&y==nd[i].y) return 1;
    		return 0;
    	}
    } vis;
    struct sNode{int f,d,l;};
    queue<sNode> Q; 
    pair<int,int> V[M];
    
    
    int main() {
    	scanf("%d%d%d",&n,&m,&mc);
    	for(int i=1; i<=n; ++i) scanf("%d",a+i);
    	for(int i=1; i<=n; ++i) scanf("%d",w+i);
    	memset(dp,inf,sizeof dp);
    	dp[0][mc]=0;
    	for(int i=1; i<=n; ++i) {
    		for(int j=a[i]; j<=mc; ++j) {
    			int x=j-a[i];
    			dp[i][x]=min(dp[i][x],dp[i-1][j]); x=min(mc,x+w[i]);
    			dp[i][x]=min(dp[i][x],dp[i-1][j]+1);
    		}
    		for(int j=0; j<=mc; ++j) D=max(D,i-dp[i][j]);
    	}
    	for(int i=1; i<=m; ++i) scanf("%d",C+i);
    	MAXC=*max_element(C+1,C+m+1);
    	Q.push((sNode){1,1,0});
    	while(Q.size()) {
    		sNode x=Q.front(); Q.pop();
    		if(x.d==D||x.f>=MAXC) continue;
    		Q.push((sNode){x.f,x.d+1,x.l+1});
    		if(x.l>1&&1LL*x.f*x.l<=MAXC&&!vis.find(x.f*x.l,x.d+1)) {
    			V[++tot]=make_pair(x.f*x.l,x.d+1);
    			vis.insert(V[tot].fr,V[tot].sc);
    			Q.push((sNode){V[tot].fr,V[tot].sc,x.l});
    		}
    	}
    	sort(V+1,V+tot+1);
    	//printf("%d %d %d
    ",D,MAXC,tot);
    	
    	for(int i=1; i<=m; ++i) {
    		if(C[i]<=D) {puts("1"); continue;}
    		int flag=0,mx=-inf;
    		for(int j=tot,k=1; j>=1; --j) {
    			while(k<tot&&V[k].fr+V[j].fr<=C[i]) mx=max(mx,V[k].fr-V[k].sc),++k;
    			if(V[j].fr-V[j].sc+mx+D>=C[i]) {flag=1; break;}
    			if(V[j].fr<=C[i]&&V[j].fr+D-V[j].sc>=C[i]) {flag=1; break;}
    		}
    		printf("%d
    ",flag);
    	}
    	return 0;
    }
    
  • 相关阅读:
    AtCoder,Codeforces做题记录
    最小割分治(最小割树):BZOJ2229 && BZOJ4519
    [BZOJ2209][JSOI2011]括号序列(splay)
    [BZOJ5461][LOJ#2537[PKUWC2018]Minimax(概率DP+线段树合并)
    [LOJ#2540][PKUWC2018]随机算法(概率DP)
    [CC-SEABUB]Sereja and Bubble Sort
    [CC-ANUGCD]Maximum number, GCD condition
    [HDU5965]扫雷
    [ZJOI2007]最大半连通子图
    [BZOJ2152]聪聪可可
  • 原文地址:https://www.cnblogs.com/nosta/p/10954408.html
Copyright © 2020-2023  润新知