ACdream群OJ 1122 数位DP
2014-07-10 16:19
288 查看
题目连接:http://acdream.info/problem?pid=1122
思路:枚举1有多少个,从0开始。如果此时1有x个,小于等于n的数字有k个。如果k>M,则M-=k,x=x+1,继续找。直到k‘<=M。其中,sum值一直累加。
然后,找有x个1,M’大的数,这个可以直接构造(假设构造出来为t)
最后,sum加上小于等于t的,有x个1的数字和(这个可以直接调用以前的函数)。
P.S. 我还是太弱,比赛的时候没敢做...
思路:枚举1有多少个,从0开始。如果此时1有x个,小于等于n的数字有k个。如果k>M,则M-=k,x=x+1,继续找。直到k‘<=M。其中,sum值一直累加。
然后,找有x个1,M’大的数,这个可以直接构造(假设构造出来为t)
最后,sum加上小于等于t的,有x个1的数字和(这个可以直接调用以前的函数)。
P.S. 我还是太弱,比赛的时候没敢做...
//#pragma comment(linker, "/STACK:102400000,102400000") #include<cstdio> #include<cstring> #include<vector> #include<queue> #include<cmath> #include<cctype> #include<string> #include<algorithm> #include<iostream> #include<ctime> #include<map> #include<set> using namespace std; #define MP(x,y) make_pair((x),(y)) #define PB(x) push_back(x) typedef long long LL; //typedef unsigned __int64 ULL; /* ****************** */ const int INF=100011122; const double INFF=1e100; const double eps=1e-8; const LL mod=1000000009; const int NN=62; const int MM=1000010; /* ****************** */ LL c[NN][NN]; LL sum[NN][NN],dp[NN][NN]; LL pow2[NN]; int a[NN]; void init(int n) { int i,j; memset(c,0,sizeof(c)); memset(sum,0,sizeof(sum)); memset(dp,0,sizeof(dp)); for(i=0;i<=n;i++)c[i][0]=c[i][i]=1; for(i=1;i<=n;i++) for(j=1;j<i;j++) c[i][j]=c[i-1][j]+c[i-1][j-1]; pow2[0]=1; for(i=1;i<=n;i++) { pow2[i]=pow2[i-1]<<1; if(pow2[i]>=mod) pow2[i]-=mod; } dp[0][0]=1; for(i=0;i<n;i++) for(j=0;j<=i;j++) if(dp[i][j]) { dp[i+1][j]+=dp[i][j]; sum[i+1][j]+=sum[i][j]; if(sum[i+1][j]>=mod) sum[i+1][j]-=mod; dp[i+1][j+1]+=dp[i][j]; sum[i+1][j+1]+=sum[i][j]; if(sum[i+1][j+1]>=mod) sum[i+1][j+1]-=mod; sum[i+1][j+1]+=pow2[i]*(dp[i][j]%mod); sum[i+1][j+1]%=mod; } } LL dfs_cnt(int pos,int need_1,bool fg) { if(pos==0) return need_1==0; if(!fg) { return dp[pos][need_1]; } int i,t; LL ans=0; for(i=0;i<=a[pos];i++) { t=need_1-(i==1); if(t>=0) ans+=dfs_cnt(pos-1,t,i==a[pos]); } return ans; } LL dfs_sum(int pos,int need_1,LL sum1,bool fg) { if(pos==0) { if(need_1==0)return sum1; return 0; } if(!fg) { LL temp=sum[pos][need_1]; temp+=(dp[pos][need_1]%mod)*sum1; temp%=mod; return temp; } int i,t; LL ans=0; for(i=0;i<=a[pos];i++) { t=need_1-(i==1); if(t>=0) { ans+=dfs_sum(pos-1,t,(sum1+pow2[pos-1]*i)%mod,i==a[pos]); if(ans>=mod) ans-=mod; } } return ans; } int fun(LL n) { int tol=0; do { a[++tol]=n&1; n>>=1; }while(n); return tol; } //不超过tol位,有n1个1,第m大 LL goo(int tol,int n1,LL m) { int i; LL ans=0; for(i=tol;i>=1;i--) { //i位放0 if(i>=n1 && c[i-1][n1]>=m) ; else { ans+=(1LL<<(i-1)); m-=c[i-1][n1]; n1--; } } return ans; } int main() { init(60); int cas,x,tol; LL n,m,temp,ans_sum,t; scanf("%d",&cas); while(cas--) { //cin>>n>>m; scanf("%lld%lld",&n,&m); m++; x=0; ans_sum=0; tol=fun(n); while(1) { temp=dfs_cnt(tol,x,1); // cout<<"num0=="<<x<<" cnt=="<<temp<<endl; if(temp>=m) break; t=dfs_sum(tol,x,0,1); ans_sum+=t; if(ans_sum>=mod) ans_sum-=mod; x++; m-=temp; } n=goo(tol,x,m); tol=fun(n); ans_sum+=dfs_sum(tol,x,0,1); if(ans_sum>=mod) ans_sum-=mod; // cout<<"ans!!! "; // cout<<n<<" "<<ans_sum<<endl; printf("%lld %lld\n",n,ans_sum); } return 0; }
相关文章推荐
- Light OJ 1122 Digit Count (简单数位DP)
- ACdream群OJ-完美数-简单数位dp
- Lightoj1122 【数位DP】
- Lightoj 1122 数位DP
- LightOj 1122 Digit Count(数位dp)
- ACDream 1064——完美数(数位DP)
- 数位dp
- HDU-3555-数位dp
- HDU 6148 数位dp
- [数位dp] spoj 10738 Ra-One Numbers
- [HDU3652]B-number && 数位DP
- 【数位dp】bzoj2089 不要62
- HDU3652 B-number(数位dp 深搜版本)
- 十四届浙江省赛 E题(数位DP)
- hdu 3555 Bomb (数位DP)
- [数形结合 数位DP] BZOJ 2917 [Poi1998]Painter’s Studio
- SPOJ - MYQ10 Mirror Number (数位DP)
- bzoj 1026 windy数|数位dp
- Light OJ 1394 Disable the Wand (数位DP)
- HDU 2089 不要62【数位dp】