Codeforces 914 C 數位DP+暴力打表+思維
阿新 • • 發佈:2019-04-24
return span 每次 amp bits sin fine inline cout ,\(1\)這個數要特判,沒特判wa了3發。。。
題意
給出一個二進制數\(n\),每次操作可以將一個整數\(x\)簡化為\(x\)的二進制表示中\(1\)的個數,如果一個數簡化為\(1\)所需的最小次數為\(k\),將這個數叫做特殊的數,
問從\(1\)到\(n\)一共有多少個特殊的數,答案對\(1e9+7\)取模。
分析
\(n\)最大為\(2^{1000}\),二進制表示中最多有\(1000\)個\(1\),所以\(n\)以內的數經過一次簡化後將變為\(1000\)以內的數,我們可以暴力打表\(1000\)以內的數簡化為\(1\)所需的最少次數,將求得的次數加\(1\)即為二進制中\(1\)的個數為\(x\)的數簡化為\(1\)所需的最少次數為\(cnt[x]\)
然後分情況討論:
- \(k=0\),答案為\(1\),只有\(1\)是經過\(0\)次簡化到\(1\)的數
\(k=1\),答案為\(n\)的位數\(-1\),\(n\)除了第\(1\)位,其余每一位為\(1\)都是特殊的數
\(k>1\),直接數位dp,設\(dp[i][j]\)為枚舉到第\(i\)位二進制中\(1\)的個數為\(j\),\(cnt[x]==k\)的數為特殊的數
Code
#include<bits/stdc++.h> #define fi first #define se second using namespace std; typedef long long ll; const double PI=acos(-1.0); const double eps=1e-6; const int inf=1e9; const int mod=1e9+7; const int maxn=1e5+10; char s[1010]; int a[1010],cnt[1010],k; ll dp[1010][1010]; ll dfs(int pos,int x,int limit){ if(pos==0) return cnt[x]==k; if(!limit&&~dp[pos][x]) return dp[pos][x]; int up=limit?a[pos]:1; ll ret=0; for(int i=0;i<=up;i++){ ret+=dfs(pos-1,x+(i==1),limit&&i==a[pos]); ret%=mod; } if(!limit) dp[pos][x]=ret; return ret; } int solve(int x){ if(x==1) return 0; int ret=0; int cnt=0; while(x){ if(x&1) cnt++; x>>=1; } ret+=solve(cnt)+1; return ret; } void init(int n){ for(int i=1;i<=n;i++){ cnt[i]=solve(i)+1; } } int main(){ ios::sync_with_stdio(false); init(1005); memset(dp,-1,sizeof(dp)); cin>>s+1>>k; int n=strlen(s+1); for(int i=1;i<=n;i++){ a[n-i+1]=s[i]-'0'; } if(k==1){ cout<<n-1; }else if(k==0) cout<<1; else cout<<dfs(n,0,1); return 0; }
Codeforces 914 C 數位DP+暴力打表+思維