「一本通 1.3 例 5」weight 题解(玄学搜索对象)

题目链接

题目描述:

已知前1.2.3....n项的前缀和 和 后缀和,记为st[],但是已经打乱,已知n个数在集合S中,求原数列。当存在多组可能的数列时,求字典序最小的数列。

题目思路:

真的玄学搜索对象,玄学时间复杂度。

暴力算法:

因为S中的数字1<=a[i]<=500,枚举每个数字a[i]。

时间复杂度500^1000.

 

优化算法:

题目中有很多限制条件,我们可以发现

sum1[k]+sum2[k+1]=all

sum1[k+1]-sum1[k]=a[i]

sum2[k+1]-sum2[k]=a[i]

而sum1[1],sum2[1]必定是最小的。

我们对于st[ ]排序,枚举每个st[i]放的位置。

它能放到前面或者后面。

前缀和或者后缀和之差在a[i]中出现过,就搜索。

可以省略很多限制条件。

理论时间复杂度:O(2^1000)

代码:

#include<bits/stdc++.h>
#define ll long long 
#define R register
using namespace std;
const int N=2000005;
int n,st[N],m,a[N],ton[N],flag,ans[N],all;
inline void dfs(R int l,R int r,R int now,R int presum,R int sufsum)
{
    if(flag)return;
    if(l==r)
    {
        R int w3=all-presum-sufsum;
        if(ton[w3])
        {
            ans[l]=w3;
            flag=1;
        }
        return;
    }
    R int w1=st[now]-presum;
    if(w1<=500&&w1>=1&&ton[w1])//属于前缀
    {
        ans[l]=w1;
        dfs(l+1,r,now+1,st[now],sufsum);
    }
    if(flag)return;
    R int w2=st[now]-sufsum;
    if(w2<=500&&w2>=1&&ton[w2])//属于后缀
    {
        ans[r]=w2;
        dfs(l,r-1,now+1,presum,st[now]);
    }
}
int main(){
    scanf("%d",&n);
    for(R int i=1;i<=2*n;i++)//前后缀和
    scanf("%d",&st[i]);
    scanf("%d",&m);
    for(R int i=1;i<=m;i++){
        scanf("%d",&a[i]);
        ton[a[i]]=1;
    }
      sort(st+1,st+2*n+1);
      all=st[2*n];
      dfs(1,n,1,0,0);
      for(R int i=1;i<=n;i++)
      printf("%d ",ans[i]);
      return 0;
}

 

 

posted @ 2018-10-31 19:15  zxza695  阅读(869)  评论(2编辑  收藏  举报

Contact with me