zoukankan      html  css  js  c++  java
  • AGC035D-Add and Remove

    题目大意

    2<=n<=18

    暴力

    4题中3题不是正解,绝了

    暴力n!过不了,优化一下

    可以发现一些不相邻的选择的顺序不影响结果,所以每次找一层同时删

    这样还是不行,考虑这么一个东西:

    假设第t层删了x,第t+1层没有删x+1,第t+2层删x+1不删x+2

    那么x+1显然可以在第t+1删掉,不会影响结果

    所以维护当前可以删的位置,当x被删掉之后下一层可以删x的前后位置,如果没有这样的就不删

    时间感觉是3^n的,发现除去两边的中间部分至少贡献2倍,那么当两边+中间*2>=ans就剪掉

    这样就卡过去了

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    #define ll long long
    //#define file
    using namespace std;
    
    int p[17],pre[18],nxt[18],n,i,j,k,l,L,st;
    ll a[18],ans,sum,sum2,s;
    
    void dg(int t,int b,int B,ll sum,ll sum2)
    {
    	int St,i;
    	if (sum+sum2>=ans) return;
    	
    	if (t>n)
    	{
    		if (st>n) {ans=sum;return;}
    		if (B)
    		dg(st,B,0,sum,sum2);
    		return;
    	}
    	
    	dg(nxt[t],b,B,sum,sum2);
    	if (b&p[t])
    	{
    		B|=p[pre[t]]|p[nxt[t]];
    		if (t==st && nxt[t]>n) sum2-=a[t]*2;
    		else
    		if (t!=st && nxt[t]<=n) sum2+=a[t]*2;
    		if (t==st) sum+=a[t],St=st,st=nxt[st]; else St=st;
    		if (nxt[t]>n) sum+=a[t];
    		
    		a[pre[t]]+=a[t];a[nxt[t]]+=a[t];
    		nxt[pre[t]]=nxt[t];pre[nxt[t]]=pre[t];
    		dg(nxt[nxt[t]],b,B,sum,sum2);
    		nxt[pre[t]]=t;pre[nxt[t]]=t;
    		a[pre[t]]-=a[t];a[nxt[t]]-=a[t];
    		
    		st=St;
    	}
    }
    
    int main()
    {
    	#ifdef file
    	freopen("agc035d.in","r",stdin);
    	#endif
    	
    	scanf("%d",&n);scanf("%lld",&sum);n-=2;st=1;
    	fo(i,1,n) scanf("%lld",&a[i]),sum2+=a[i],p[i]=1<<(i-1),nxt[i]=i+1,pre[i]=i-1;
    	L=p[n]*2-1;nxt[n+1]=n+1,pre[n+1]=n;sum2*=2;
    	scanf("%d",&j),sum+=j;
    	
    	if (n<=0) {printf("%lld
    ",sum);return 0;}
    	
    	ans=9223372036854775807ll;
    	dg(1,L,0,sum,sum2);
    	
    	printf("%lld
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    

    题解

    考虑倒推,对于区间[l,r]求最后一个被删掉的数i

    形式化一下,求区间[l,r]中删掉i后i往左边贡献x次,往右边贡献y次后的答案

    那么a[i]的贡献是a[i]*(x+y),[l,i-1]中往左贡献x次,往右会先走到i再往两边,所以会贡献x+y次,[i+1,r]类似

    直接递归计算即可

    关于时间复杂度,状态数时n^2*2^n的,因为每对(x,y)会转移到(x,x+y)和(x+y,y)上,而区间个数又是n^2

    也许吧我也不会算

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define min(a,b) (a<b?a:b)
    #define ll long long
    //#define file
    using namespace std;
    
    int n,i,j,k,l;
    ll a[19];
    
    ll dg(int l,int r,ll x,ll y)
    {
    	ll s,ans=9223372036854775807ll;
    	int i;
    	
    	if (l>r) return 0;
    	
    	fo(i,l,r)
    	{
    		s=dg(l,i-1,x,x+y)+dg(i+1,r,x+y,y)+a[i]*(x+y);
    		ans=min(ans,s);
    	}
    	return ans;
    }
    
    int main()
    {
    	#ifdef file
    	freopen("agc035d.in","r",stdin);
    	#endif
    	
    	scanf("%d",&n);
    	fo(i,1,n) scanf("%lld",&a[i]);
    	
    	printf("%lld
    ",dg(2,n-1,1,1)+a[1]+a[n]);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    mac 配置 iterm2
    python面试题
    待办事项--flask
    八皇后问题c语言版(xcode下通过)
    对分布式一些理解
    观察者模式
    用redis实现悲观锁(后端语言以php为例)
    只用200行Go代码写一个自己的区块链!(转)
    php的生命周期的概述
    linux网络编程1 最简单的socket编程
  • 原文地址:https://www.cnblogs.com/gmh77/p/12896436.html
Copyright © 2011-2022 走看看