[APIO2015]Bali Sculptures

看到这种求位运算的问题一定要想直接对答案贪心啊,从高位枚举到低位,设当前的位为pos,pos之前贪心得到的答案为ans。
现在的问题就是能否找到一种方案,使得pos这一位为0,而且满足这种方案算出来的答案的前若干位与ans相同。
考虑设f[i][j]表示前i个数,分j份能否满足条件,0为满足,若存在一个k使得 f[k][j1]==0,(s[i]s[k])and(1<<pos)==0,(((ans|((s[i]s[j])))>>pos))==(ans>>pos)
则f[i][j]=0.这样做是 n3log 的。
对于最后一个子任务,考虑到a=1,还是按位贪心,设g[i]表示前i个数至少分多少块满足条件,g[n]与b比较即可。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<map>
#include<climits>
#include<cmath>
#define DB double
#define X first
#define Y second
#define MP make_pair
#define INF 0x3f3f3f3f
#define LL long long
#define pii pair<int,int>
#define pll pair<LL,LL>
#define int LL
#define DEBUG(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
template<typename T>void Read(T& x)
{
    x=0;char c;int flag=0,sgn=1;
    while(c=getchar())
    {
        if(c=='-')sgn=-1;
        else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;
        else if(flag)break;
    }
    x*=sgn;
}
const int MAXN=2001;
LL f[MAXN][MAXN],n,a,b,g[MAXN],ans=0,num[MAXN],s[MAXN];
void fucker()
{
    f[0][0]=0;
    for(int i=1;i<MAXN;i++)f[0][i]=1;
    for(int pos=59;pos>=0;pos--)
    {
        if(pos==1)
            pos=1;
        int flag=1LL;
        for(int k=1;k<=b;k++)
            for(int i=k;i<=n;i++)
            {
                f[k][i]=1LL;
                for(int j=k-1;j<i;j++)
                {
                    bool a=(((s[i]-s[j])&(1LL<<(pos))))==0,b=((((ans|((s[i]-s[j])))>>pos))==(ans>>pos));
                    f[k][i]=min(f[k][i],f[k-1][j]==0&&a&&b?0LL:1LL);
                }
            }
        for(int k=a;k<=b;k++)
            if(f[k][n]==0)flag=0;
        ans|=(flag<<pos);
    }
    cout<<ans<<endl;
}
void lover()
{
    for(int pos=60;pos>=0;pos--)
    {
        for(int i=1;i<=n;i++)
        {
            g[i]=(LL)INF;
            for(int j=0;j<i;j++)
            {   
                int tmp=0;
                bool a=((((s[i]-s[j])&(1LL<<pos)))==0),b=((((ans|((s[i]-s[j])))>>pos))==(ans>>pos));
                if(a&&b)
                    tmp=g[j]+1;
                else
                    tmp=3000;
                //DEBUG("%lld %lld\n",g[i],tmp);
                g[i]=min(g[i],tmp);
            }
        }
        if(g[n]>b)ans|=(1LL<<pos);//printf("%lld\n",pos);
    }
    cout<<ans<<endl;
}
main()
{
    freopen("bali.in","r",stdin);
    freopen("bali.out","w",stdout);
    Read(n),Read(a),Read(b);
    for(int i=1;i<=n;i++)
        Read(num[i]),s[i]=num[i]+s[i-1];
    if(a==1)lover();
    else fucker();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值