zoukankan      html  css  js  c++  java
  • CF914C Travelling Salesman and Special Numbers

    题目描述

    对于一个正整数x,我们定义一次操作是将其变为它二进制下“1”的个数,比如我们知道1310=11012 ,而1101有三个"1",所以对13进行一次操作就会将其变为3。显而易见的是,对于一个正整数,我们在进行若干次操作后,一定会将其变为1。

    给定n和k,其中n是在二进制下被给出,求出所有不大于n且将其变为1的最小操作次数为k的数的个数对10^9+7取模的结果。

    1<=n<21000, 0<=k<=10000

    题解

    因为n在二进制下长度最大为1000,所以最多有1000个1,所以转化一次最多是1000。

    我们可以处理出当前数为x时还需要几步到1,cnt[i]=cnt[sum[i]]+1,sum[i]为i在二进制下有多少个1,sum[i]=sum[i^lowbit(i)]+1,i^lowbit(i)就是i在二进制下去掉最右边的1,这个数一定先处理出来了,所以就可以递推,x在1000以内。

    然后就可以进行数位DP,f[s][num][lim]表示当前处理到第i位,1的个数为num

    那么最后cnt[num]+1==k就是一种,num就是枚举出的数转换一次得到的。

    然后就WA了....

    考虑k=0时,会输出0,但是容易发现1就是一个解,这是因为cnt是操作了一次之后,而1不需要操作,所以特判k=0即可。

    k=1时,答案会多2,这是因为0和1的关系,所以把cnt[0]设成负数,然后特判k=1时答案-1即可。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int mod=1000000007;
    const int maxn=1005;
    char s[maxn];
    int k,len,num[maxn];
    int sum[maxn],cnt[maxn];
    int f[maxn][maxn][2];
    
    void init(){
        sum[0]=0;
        cnt[1]=0;
        cnt[0]=-2;
        for(int i=1;i<=1000;i++) sum[i]=sum[i^(i&-i)]+1;
        for(int i=2;i<=1000;i++) cnt[i]=cnt[sum[i]]+1;
    }
    
    int dfs(int s,int c,bool lim){
        if(!s) return cnt[c]+1==k;
        if(f[s][c][lim]!=-1) return f[s][c][lim];
        int mx= lim ? num[s] : 1;
        int ret=0;
        for(int i=0;i<=mx;i++)
         ret=(ret+dfs(s-1,c+(i==1),lim&&i==mx))%mod;
        return f[s][c][lim]=ret;
    }
    
    int cx(){
        memset(f,-1,sizeof(f));
        return dfs(len,0,true);
    }
    
    int main(){
        init();
        scanf("%s%d",s,&k);
        if(!k){printf("1");return 0;}
        len=strlen(s);
        for(int i=1;i<=len;i++) num[i]=s[len-i]-'0';
        int ans=cx();
        if(k==1) ans--;
        printf("%d",ans);
    }
    View Code

    网上都是什么组合数,明明就有数位DP的标签(掩饰自己不会组合数)

  • 相关阅读:
    【Dos-BatchPrograming】04
    【Dos-BatchPrograming】03
    【Dos-BatchPrograming】02
    【Dos-BatchPrograming】01
    【perl】01
    【Linux】Re04
    【Linux】Re03
    【Linux】Re02
    【Linux】Re01
    【C++】01
  • 原文地址:https://www.cnblogs.com/sto324/p/11401958.html
Copyright © 2011-2022 走看看