3780: 数字统计
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 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
3 1
001 101
Sample Output
11
HINT
对于全部的数据,1<=M<=200,1<=T<=50。
Source
题解:数位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 203
using 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;//01
if (a[1]<=1&&b[1]>=1) f[1][0][a[1]==1?1:0][b[1]==1?1:0]+=one;//10
if (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;
}
}