【题解】CF8E Beads

CF8E Beads

确实不会做。。。

显然满足题意的二进制串的首位必须是 0 0 0。考虑一位一位地确定答案串。假设已经确定了答案串的前k位,我们假设第 k + 1 k+1 k+1 位是 0 0 0,则要设法统计出满足条件的串的个数 s s s。 那么如果 s < m s<m s<m,则答案串第 k + 1 k+1 k+1 位为 1 1 1 ,同时 m = m − s m=m−s m=ms ;否则答案串第 k + 1 k+1 k+1 位为 0 0 0。于是问题转化为,统计所有长度为 n n n 的,前缀为 p r e f i x prefix prefix 的二进制串中,满足题目要求的串的个数。 这是一类与数位有关的统计问题,于是很容易想到数位 d p dp dp

那么考虑 d p i , j , r e v , i n v dp_{i,j,rev,inv} dpi,j,rev,inv 表示,当前已经确定了前 i i i 位和末 j j j 位, r e v rev rev 表示前 i i i 位与末 j j j 位的逆序是否相等, i n v inv inv 表示前 i i i 位与末 j j j 位的逆序取反后是否相等。状态转移比较显然,我们枚举第 i + 1 i+1 i+1 位和第 n − i n−i ni 位的取值,如果它满足 p r e f i x prefix prefix 的限制,且新的串没有违反题目要求, 那么更新 r e v rev rev i n v inv inv 的状态,并累加到对应的新状态上。

#include<bits/stdc++.h>
using namespace std;
long long n,k;
long long dp[55][2][2];
int a[55];
long long dfs(int pos,int lim1,int lim2) {
	if(pos<n-pos+1) return 1;
	if(dp[pos][lim1][lim2]>=0) return dp[pos][lim1][lim2];
	long long tot=0;
	for(int i=0;i<=1;i++)
	    if(a[pos]==i||a[pos]==-1) {
	    	for(int j=0;j<=1;j++)
	    	    if(a[n-pos+1]==j||a[n-pos+1]==-1) {
	    	    	if(lim1&&i>j||lim2&&i>!j||pos==n-pos+1&&i!=j) continue;
	    	    	tot+=dfs(pos-1,lim1&&(i==j),lim2&&(i==!j));
				}
		} 
    return dp[pos][lim1][lim2]=tot;
}
int main() {
	scanf("%lld%lld",&n,&k),k++;
	memset(a,-1,sizeof(a)),memset(dp,-1,sizeof(dp)),a[n]=0;
	long long nw=dfs(n,1,1);
	if(nw<k) {
		printf("-1");
		return 0;
	}
	for(int i=n-1;i>=1;i--) {
		a[i]=0,memset(dp,-1,sizeof(dp));
		long long nw=dfs(n,1,1);
		if(nw<k) {
			k-=nw,a[i]=1;
		} 
	}
	for(int i=n;i>=1;i--) printf("%d",a[i]);
}
posted @ 2021-05-01 10:20  仰望星空的蚂蚁  阅读(17)  评论(0)    收藏  举报  来源