您的位置:首页 > 其它

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. 我还是太弱,比赛的时候没敢做...

//#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: