垃圾T*B,推荐了这道题给我自己又弃了。。
然后我做了半天没有做出来
然后暴力DP大家都会
然后优化一下
然后有个地方口头AC很简单,然后打起来不是很会
脑子有点乱,暂时弃坑
#include<cstdio>
#include<cstring>
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 x<y?x:y;}
int 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<<i-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;
}