superoj921 编译优化

来源:互联网 发布:淘宝被降权是什么意思 编辑:程序博客网 时间:2024/06/06 09:45

分析:

        此题为一个环,告诉你环上的权值,求最大选择和;

选择要求:选了A,与A相邻的俩个元素就不能选。

数据 60% n=5000

       100% n=200000

我65分dp

60% dp

       dp[i][j]=max(dp[i-1][j],dp[i-2][j-1]+a[i]);

       再多旋转几圈防止1和n冲突           复杂度O(N^2)

代码:

#include<cmath>#include<algorithm>#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>//#include<ctime>using namespace std;int n,m;int a[5010];int b[5010];int dp[5010][5010];int ans;int read(){int k=0,f=1;    char c=getchar();while(c>'9'||c<'0') {if(c=='-') f=-1; c=getchar();}while(c>='0'&&c<='9') {k=k*10+(c-'0'); c=getchar();}return k*f;}int main(){   freopen("compile.in","r",stdin);   freopen("compile.out","w",stdout);   int i,j,k;   n=read();   m=read();   if(m>(n>>1)) {cout<<"Error!";return 0;}   for(i=1;i<=n;i++)     {     a[i]=read(); }      for(i=1;i<=n;i++)     for(j=1;j<=m;j++) dp[i][j]=-1000000000;      dp[1][1]=a[1];   dp[2][1]=max(a[1],a[2]);          for(i=3;i<=n;i++)     for(j=1;j<=min(m,(n+1)>>1);j++)       {         dp[i][j]=max(dp[i-2][j-1]+a[i],dp[i-1][j]);   }   ans=dp[n][m];      k=0;   for(i=n/3;i<=n;i++)       b[++k]=a[i];    for(i=1;i<n/3;i++)        b[++k]=a[i];   for(i=1;i<=n;i++) a[i]=b[i];           for(i=1;i<=n;i++)     for(j=1;j<=m;j++) dp[i][j]=-1000000000;        dp[1][1]=a[1];   dp[2][1]=max(a[1],a[2]);          for(i=3;i<=n;i++)     for(j=1;j<=min(m,(n+1)>>1);j++)       {         dp[i][j]=max(dp[i-2][j-1]+a[i],dp[i-1][j]);   }   ans=min(dp[n][m],ans);      k=0;   for(i=n/2+1;i<=n;i++)       b[++k]=a[i];    for(i=1;i<=n/2;i++)        b[++k]=a[i];   for(i=1;i<=n;i++) a[i]=b[i];           for(i=1;i<=n;i++)     for(j=1;j<=m;j++) dp[i][j]=-1000000000;        dp[1][1]=a[1];   dp[2][1]=max(a[1],a[2]);          for(i=3;i<=n;i++)     for(j=1;j<=min(m,(n+1)>>1);j++)       {         dp[i][j]=max(dp[i-2][j-1]+a[i],dp[i-1][j]);   }   ans=min(dp[n][m],ans);         cout<<ans;        return 0;}

100%数据

       利用网络流残余流量思想(并不懂)

       建立大根堆,维护权值和映射

       用了B,就废掉A,C,再加入A+C-B

 若下一次选了A+C-B 则总和为A+C

       实现过程用的queue

       因为要修改左右元素是什么,而queue里面没有编号无法修改queue内的内容(例如迪杰斯特拉的手写堆是因为修改dis为queue内排序基准),

所以要用映射。

       每个queue记录权值和映射,映射表示它在queue外普通int数组的编号,修改时直接修改int数组的值,queue内元素映射出来自然就是修改后的值了

左右元素用l,r储存(like dancing link)l[i]=l[l[i]],r[l[i]]=i...........     ban判断是否废掉了(删点方法2333)

AC代码:

//queue内开映射 #include <iostream>#include <vector>#include <algorithm>#include <stack>#include <cstdlib>#include <cstdio>#include <map>#include <cstring>#include <queue>#include <string>#define N 200100#define INF (int)1e9using namespace std;struct node {    int v;    int p;     //映射     bool  operator < (const node &a)const    {        return v<a.v;    }};priority_queue <node> q;int n;int m;int a[N];int l[N];int r[N];bool ban[N];int ans;int main (){    //freopen("cs.in","r",stdin);    //freopen("cs.out","w",stdout);    scanf("%d%d",&n,&m);    if(m>n/2)    {        printf("Error!\n");        return 0;    }    for(int i=1;i<=n;i++)    {        scanf("%d",&a[i]);        l[i]=i-1;r[i]=i+1;        node t;t.v=a[i];t.p=i;         q.push(t);    }    l[1]=n;r[n]=1;    for(int i=1;i<=m;i++)    {        while(ban[q.top().p])q.pop();           int w=q.top().v;        int x=q.top().p;        q.pop();        ans+=w;        a[x]=a[l[x]]+a[r[x]]-a[x];        ban[l[x]]=ban[r[x]]=true;        l[x]=l[l[x]];r[x]=r[r[x]];        r[l[x]]=x;l[r[x]]=x;        node t;t.v=a[x];t.p=x;         q.push(t);    }    cout<<ans;    return 0;    }





0 0
原创粉丝点击