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;
}
原文地址:https://www.cnblogs.com/gmh77/p/12896436.html