bzoj 3780: 数字统计 (数位dp)

来源:互联网 发布:如何手机投诉淘宝卖家 编辑:程序博客网 时间:2024/06/05 11:08

3780: 数字统计

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 50  Solved: 27
[Submit][Status][Discuss]

Description

小A正在研究一些数字统计问题。有一天他突然看到了一个这样的问题:
将[L..R]中的所有整数用M位二进制数表示(允许出现前导0)。现在将这些数中的每一个作如下变换:
从这个数的最低两位开始,如果这两位都是0,那么X=1,否则X=0。现在将这两位删去,然后将X放在原来最低位的位置上。重复这个变换直到这个数只剩下一位为止。
例如01001的变换过程如下:
01001-->0100-->011-->00-->1。
现在的问题是变换后的所有数中,值为Y(Y为0或1)的有多少个?
小A不会了,他想让你帮助他完成这个问题。

Input

输入文件包含多组测试数据。
第一行,一个整数T,表示测试数据的组数。
接下来的T节,每节对应一组测试数据,格式如下:
第一行,两个整数M、Y。
第二行,两个M位二进制数L、R。

Output

对于每组测试数据,输出一行,一个二进制数,表示该组测试数据中[L..R]中的所有整数变换后的值为Y的个数。这里的二进制数不允许出现前导0。

Sample Input

1
3 1
001 101

Sample Output

11

HINT

对于全部的数据,1<=M<=200,1<=T<=50。


Source

[Submit][Status][Discuss]

题解:数位dp

这道题要写二进制高精哦。。。

我们先看上面的变换,正常来看应该是从低位向高位填,每次将填好的最后两个变成他要求的0或1,但是这样推没法控制上下界。那么倒着看上面的变换过程00->1 这个其实第一位的0就是原数的0,那么也就是每次由一位变成两位,这两位中的第一个一定是与原数一致的,第二个表示的是下面两位的变换。

f[i][j][0/1][0/1]表示的是确定到第i位,下面两位的变换结果为j,是否卡上下界。

#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#define N 203using namespace std;int n,m;int a[N],b[N],t,st[N],top,opt;char s[N];struct number{int s[300],len;number(){memset(s,0,sizeof(s));len=0;}number operator + (const number &a){number c;int t=max(a.len,len);for (int i=1;i<=t;i++) c.s[i]=s[i]+a.s[i];for (int i=1;i<=t;i++) {c.s[i+1]+=(c.s[i]/2);c.s[i]%=2;}while (c.s[t+1]) {t++; c.s[t+1]+=(c.s[t]/2);c.s[t]%=2;}c.len=t;return c;}number operator += (const number &a){*this=*this+a;return *this;}}ans,f[N][3][3][3],one;bool pd(int x,int y){if (x!=y||x==1&&y==1) return true;return false;}void solve(int x){int cnt=0;while (x) {st[++cnt]=x%2;x/=2;}for (int i=cnt;i>=1;i--) printf("%d",st[i]);printf("\n");}int main(){freopen("a.in","r",stdin);freopen("my.out","w",stdout);scanf("%d",&t);one.len=1;one.s[1]=1;for (int T=1;T<=t;T++) {scanf("%d%d",&n,&opt);scanf("%s",s+1); for (int j=1;j<=n;j++)  a[j]=s[j]-'0';scanf("%s",s+1);for (int j=1;j<=n;j++)  b[j]=s[j]-'0';//for (int i=1;i<=n;i++) cout<<a[i]<<" "; cout<<endl;//for (int i=1;i<=n;i++) cout<<b[i]<<" "; cout<<endl;memset(f,0,sizeof(f)); ans=number();if (!opt) {if (a[1]<=0&&b[1]>=0) f[1][1][a[1]==0?1:0][b[1]==0?1:0]+=one;//01if (a[1]<=1&&b[1]>=1) f[1][0][a[1]==1?1:0][b[1]==1?1:0]+=one;//10if (a[1]<=1&&b[1]>=1) f[1][1][a[1]==1?1:0][b[1]==1?1:0]+=one;//11}else { if (a[1]!=0) { printf("0\n"); continue; } f[1][0][a[1]==0?1:0][b[1]==0?1:0]+=one;    }    for (int i=1;i<=n-1;i++)     for (int j=0;j<=1;j++)    for (int a1=0;a1<=1;a1++)      for (int b1=0;b1<=1;b1++)        if (f[i][j][a1][b1].len!=0) {        //cout<<i<<" "<<j<<" "<<a1<<" "<<b1<<" "<<f[i][j][a1][b1]<<endl;        if (!j) {        if (a1&&b1) {          if (a[i+1]<=0&&b[i+1]>=0) f[i+1][1][a[i+1]==0?1:0][b[i+1]==0?1:0]+=f[i][j][a1][b1];              if (a[i+1]<=1&&b[i+1]>=1) f[i+1][0][a[i+1]==1?1:0][b[i+1]==1?1:0]+=f[i][j][a1][b1];              if (a[i+1]<=1&&b[i+1]>=1) f[i+1][1][a[i+1]==1?1:0][b[i+1]==1?1:0]+=f[i][j][a1][b1];}else if (a1) {  if (a[i+1]<=0) f[i+1][1][a[i+1]==0?1:0][0]+=f[i][j][a1][b1];              if (a[i+1]<=1) f[i+1][0][a[i+1]==1?1:0][0]+=f[i][j][a1][b1];              if (a[i+1]<=1) f[i+1][1][a[i+1]==1?1:0][0]+=f[i][j][a1][b1];}else if (b1) {  if (b[i+1]>=0) f[i+1][1][0][b[i+1]==0?1:0]+=f[i][j][a1][b1];              if (b[i+1]>=1) f[i+1][0][0][b[i+1]==1?1:0]+=f[i][j][a1][b1];              if (b[i+1]>=1) f[i+1][1][0][b[i+1]==1?1:0]+=f[i][j][a1][b1];}else {  f[i+1][1][0][0]+=f[i][j][a1][b1];              f[i+1][0][0][0]+=f[i][j][a1][b1];              f[i+1][1][0][0]+=f[i][j][a1][b1];}}else {if (a1&&b1) { if (a[i+1]<=0&&b[i+1]>=0)  f[i+1][0][a[i+1]==0?1:0][b[i+1]==0?1:0]+=f[i][j][a1][b1];}else if (a1) {if (a[i+1]<=0) f[i+1][0][a[i+1]==0?1:0][0]+=f[i][j][a1][b1];}else if (b1) {if (b[i+1]>=0) f[i+1][0][0][b[i+1]==0?1:0]+=f[i][j][a1][b1];}else f[i+1][0][0][0]+=f[i][j][a1][b1];    }}    for (int i=0;i<=1;i++)      for (int a1=0;a1<=1;a1++)       for (int b1=0;b1<=1;b1++)     { if (a1&&b1) {   if (i>=a[n]&&i<=b[n]) ans+=f[n-1][i][a1][b1]; } else if (a1) { if (i>=a[n]) ans+=f[n-1][i][a1][b1]; } else if (b1) { if (i<=b[n]) ans+=f[n-1][i][a1][b1]; } else ans+=f[n-1][i][a1][b1];    }    if (ans.len) {    for (int i=ans.len;i>=1;i--) printf("%d",ans.s[i]);    printf("\n");}    else printf("0\n");    //cout<<ans<<endl;}}



1 0