16ECFinal B(数位DP)

题目链接:http://codeforces.com/gym/101194

题意:定义半回文数a为将二进制数a的奇数位和偶数位分别提出来,如果奇数位或者偶数位为回文数则a为半回文数,求长度为n的第k个半回文数

这个题目需要思考一下DP状态应该是什么,直接dfs应该是不行的,因为这个后效性要去除比较困难,不过好在这题对数的大小没有限制,所以可以不用dfs做了。。

然后猴了n遍后发现,要处理填完前i位的条件下的半回文数个数,这个可以分为偶数位回文和奇数位回文和奇偶都回文容斥一下就可以。。

然后从高到低就分别决定各个位的01即可。。

是个反套路的数位DP,依赖套路会花很多时间。。

 

 

 

/**
 *          ┏┓    ┏┓
 *          ┏┛┗━━━━━━━┛┗━━━┓
 *          ┃       ┃  
 *          ┃   ━    ┃
 *          ┃ >   < ┃
 *          ┃       ┃
 *          ┃... ⌒ ...  ┃
 *          ┃              ┃
 *          ┗━┓          ┏━┛
 *          ┃          ┃ Code is far away from bug with the animal protecting          
 *          ┃          ┃   神兽保佑,代码无bug
 *          ┃          ┃           
 *          ┃          ┃        
 *          ┃          ┃
 *          ┃          ┃           
 *          ┃          ┗━━━┓
 *          ┃              ┣┓
 *          ┃              ┏┛
 *          ┗┓┓┏━━━━━━━━┳┓┏┛
 *           ┃┫┫       ┃┫┫
 *           ┗┻┛       ┗┻┛
 */ 
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-12
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define NM 100005
#define nm 1055
#define pi 3.1415926535897931
const ll inf=4e18;
using namespace std;
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
    return f*x;
}
 
 





int n,ans[NM],ca;
ll k,p[64];
bool odd,even,_odd,_even;

ll get(int x){if(x<62)return p[x];else return inf;}
bool bit(int x){
    if(n%2)return ans[n-x+1]==-1||ans[n-x+1]==ans[x];
    if(x%2)return ans[n-x]==-1||ans[n-x]==ans[x];
    else return ans[n-x+2]==-1||ans[n-x+2]==ans[x];
}

ll calc(int t){
    ll s=0;
    if(_even)s+=get( max( (n/2+1)/2-t/2 ,0) + (n+1)/2-(t+1)/2);
    if(_odd)s+=get( max( ((n+1)/2+1)/2-(t+1)/2 ,0) + n/2-t/2);
    if(_even&&_odd)s-=get( max( ((n+1)/2+1)/2-(t+1)/2 ,0) + max(0,(n/2+1)/2-t/2));
    return s;
}

int main(){
    p[0]=1;inc(i,1,62)p[i]=p[i-1]<<1;
    int _=read();while(_--){
	n=read();k=read();
	odd=even=_odd=_even=true;
	printf("Case #%d: ",++ca);
	if(calc(0)<k){printf("NOT FOUND!\n");continue;}
	inc(i,1,n)ans[i]=-1;
	inc(i,1,n){
	    ll s=0;
	    ans[i]=0;
	    _odd=odd;_even=even;
	    if(i%2)_odd=odd&&bit(i);else _even=even&&bit(i);
	    s=calc(i);
	    if(s==0||s<k)k-=s,ans[i]=1;
	    if(i%2)odd=odd&&bit(i);else even=even&&bit(i);
	}
	inc(i,1,n)printf("%d",ans[i]);putchar('\n');
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值