【题解】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=m−s ;否则答案串第 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 n−i 位的取值,如果它满足 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]);
}

浙公网安备 33010602011771号