4937: [Ceoi2016]popeala

垃圾T*B,推荐了这道题给我自己又弃了。。
然后我做了半天没有做出来
然后暴力DP大家都会
然后优化一下
然后有个地方口头AC很简单,然后打起来不是很会
脑子有点乱,暂时弃坑

#include
#include
typedef long long LL;
const int N=55;
const int M=200005;
const int MAX=1<<30;
char ss[N][M];
int n,m,S;
int f[N][M];
int a[N];
int mymin (int x,int y){return xint mymax (int x,int y){return x>y?x:y;}
void init ()
{
    scanf("%d%d%d",&n,&m,&S);
    for (int u=1;u<=m;u++) scanf("%d",&a[u]);
    for (int u=1;u<=m;u++) a[u]=a[u]+a[u-1];
    for (int u=1;u<=n;u++)   scanf("%s",ss[u]+1);
}
struct qq
{
    int l,r;
    int s1,s2;
    LL c;
}s[M*2];int num=0;//这两位 
void bt (int l,int r)
{
    int a=++num;
    s[a].l=l;s[a].r=r;
    s[a].c=0;
    if (l==r)
    {
        for (int i=1;i<=n;i++)
            if (ss[i][l]=='1')
                s[a].c=s[a].c+(1LL<1);
        return ;
    }
    int mid=l+r>>1;
    s[a].s1=num+1;bt(l,mid);
    s[a].s2=num+1;bt(mid+1,r);
    s[a].c=s[s[a].s1].c&s[s[a].s2].c;
}
int find (int now,int l,int r)
{
    if (s[now].l==l&&s[now].r==r)
        return s[now].c;
    int mid=(s[now].l+s[now].r)>>1;
    int s1=s[now].s1,s2=s[now].s2;
    if (r<=mid) return find(s[now].s1,l,r);
    else if (l>mid) return find(s[now].s2,l,r);
    else return find(s[now].s1,l,mid)&find(s[now].s2,mid+1,r);
}
int Get (int x)
{
    int cnt=0;
    while (x>0)
    {
        x=x&(x-1);
        cnt++;
    }
    return cnt;
}
int get (int x,int y)//我们想得到从l~r的值 
{
    int xx=find(1,x,y);
    return Get(xx)*(a[y]-a[x-1]);
}
void solve ()
{
    num=0;
    for (int u=1;u<=S;u++)//可以分成多少段 
    {
        for (int i=1;i<=m;i++)//终点
        {
            for (int j=u;j<=i;j++)//起点在哪里
                f[u][i]=mymin(f[u][i],f[u-1][j-1]+get(j,i));
        }
    }
    for (int u=1;u<=S;u++) printf("%d\n",f[u][m]);
}
int main()
{
    init();
    bt(1,m);
    solve();
    return 0;
}

你可能感兴趣的:(坑)