UOJ 110 [APIO2015]Bali Sculptures

来源:互联网 发布:卖血哥玩的软件是什么 编辑:程序博客网 时间:2024/05/09 04:13

贪心+二进制按位DP

我们需要让答案尽量小,即让答案的二进制位的高位尽量为0。可以一位一位做,同时要保证前面做过的位的答案不变。

前4个子任务,记f[i][j]表示前i个数分成j组,且符合当前答案的方案是否存在。那么它可以从一个合法的f[k][j-1] (k < i) 转移过来。这样是O(n^3*logn)的。

第5个子任务用上面的方法会T。考虑到A=1,即没有分组下界。记g[i]表示前i个数符合当前答案最少要分几组。那么它同样可以从一个合法的g[k]转移过来。这样是O(n^2)的。

#include<cstdio>#include<algorithm>#define N 2005#define ll long longusing namespace std;const int INF = 2333;int n, a, b, len=0, g[N];bool f[105][105];ll pre[N], pos, ans;void solve2(){    for(pos>>=1;pos;pos>>=1,len--)    {        f[0][0]=1;        for(int i = 1; i <= n; i++)            for(int j = 1; j <= i; j++)            {                f[i][j]=0;                for(int k = 0; k < i; k++)                {                    ll temp = pre[i]-pre[k];                    if(f[k][j-1] && ((temp>>len)|ans)==ans && (temp&pos)==0)                    {                        f[i][j]=1;                        break;                    }                }            }        ans<<=1;        ans^=1;        for(int i = a; i <= b; i++)            if(f[n][i])            {                ans^=1;                break;            }       }}void solve1(){    for(pos>>=1;pos;pos>>=1,len--)    {        for(int i = 1; i <= n; i++)        {            g[i]=INF;            for(int j = 0; j < i; j++)            {                ll temp = pre[i]-pre[j];                if(((temp>>len)|ans)==ans && (temp&pos)==0)                {                    g[i]=min(g[i],g[j]+1);                }            }        }        ans<<=1;        if(g[n]>b)ans^=1;    }}int main(){    scanf("%d%d%d",&n,&a,&b);    for(int i = 1; i <= n; i++)    {        scanf("%lld",&pre[i]);        pre[i]+=pre[i-1];    }    for(pos=1;pos<=pre[n];pos<<=1)len++;    if(a!=1)solve2();    else solve1();    printf("%lld\n",ans);} 
0 0
原创粉丝点击