数位dp抢救一波

版权声明:本文为博主原创文章,如果转走了就评论说一声就好了哈。 https://blog.csdn.net/qq_36124802/article/details/82804451

HDU3652:

T组数据

找到1-n之间包含13这个子串并且能被13整除的数字个数。

dp[i][j][k]表示计算到第i位,目前%结果为j且需要k状态才满足题意。

这里k为2:表示不缺13这个子串的个数

k为1:表示上一个数末尾为1,此时缺一个3可以组成13

k为0:表示之前没有13,仍然缺13.

dps(i,mod,k,limit)表示找到i位,%为mod,状态满足k的个

  1. #include<bits/stdc++.h>
    using namespace std;
    const int maxn=5e5+7;
    typedef long long ll;
    ll dp[25][25][3];
    ll digit[25];
    //dp[i][j][k],
    //i位,mod13的结果为j,
    //0:不包含1,3.
    //1:末尾为1
    //2:剩下的里面有1,3了
    ll yu[25];
    ll dfs(ll len,ll mod,ll end_x,bool limit){
        if(len==0){
            //cout <<" --- " << len <<"   "<<mod << "   "<<end_x<<"   "<<limit << endl;
            if(mod==0&&end_x==2)return 1;
            return 0;
        }
        if(!limit&&dp[len][mod][end_x])return dp[len][mod][end_x]; //,没有限制长度并且后面记录过了
        ll up_bound,cnt=0;
        if(limit)
        up_bound=digit[len];
        else
        up_bound=9;
        ll new_x,new_mod;
     //   cout <<"in   " <<len <<"   mod= " <<mod <<"  end_x" << end_x <<"  "<<up_bound << endl;
        for(ll i=0;i<=up_bound;i++){
            new_mod=((mod+i*yu[len-1]))%13;
    /*  cout <<i <<"aaa   " <<len <<"   mod= " <<mod <<"  end_x" << end_x <<"  "<<up_bound <<
      "     " <<new_mod <<endl;*/
    
            if(end_x==2) //如果已经全部有了,那就随便要,但是%13==0
            cnt+=dfs(len-1,new_mod,2,limit&&i==up_bound);
            else if(end_x==1&&i==3) //已经末尾为1,那么要3可以变成2
            cnt+=dfs(len-1,new_mod,2,limit&&i==up_bound);
            else if(i==1)//不管前面是什么,要个1进去就只缺一个3了
            cnt+=dfs(len-1,new_mod,1,limit&&i==up_bound);
            else //啥也没有那么啥也都还要
            cnt+=dfs(len-1,new_mod,0,limit&&i==up_bound);
        }
        if(!limit)dp[len][mod][end_x]=cnt; //注意这里需要不为limit,不然后面会有限制
        return cnt;
    }
    ll solve(ll x){
        int k=0;
        long long g1=1;
        yu[0]=g1;
        for(int i=1;i<=12;i++){
            g1*=10LL;
            yu[i]=g1%13;
        }
        while(x){
            digit[++k]=x%10;
            x/=10;
        }
        dfs(k,false,false,true);
    }
    int main(){
        int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
        //freopen("in.txt","r",stdin);
        int T;
        ll g1,g2,g3,g4;
        while(cin >> g1){
        cout << solve(g1) << endl;
        }
        return 0;
    }
    

    Educational Codeforces Round 50 (Rated for Div. 2)

  2. 给一个[L,R],求L->R之间非0数量小于3的个数

  3. dp[i][j]表示dp到第i位,目前剩j个非0位

  4. 那么每次循环中如果是否0,且num>0,则还可以有非0位,否则不加这个数字

  5. 如果是循环到0,num可以获取的数量不变,正常计算即可

  6. #include<bits/stdc++.h>
    using namespace std;
    const long long maxn=5e5+7;
    typedef long long ll;
    ll dp[25][4];
    ll digit[25];
    ll yu[25];
    ll dfs(ll len,ll num,bool limit){
        if(len==0){
            return 1;
        }
        if(!limit&&dp[len][num])return dp[len][num]; //,没有限制长度并且后面记录过了
        ll up_bound,cnt=0;
        if(limit)
        up_bound=digit[len];
        else
        up_bound=9;
        for(long long i=0;i<=up_bound;i++){
            if(i!=0){
            if(num>0)
            cnt+=dfs(len-1,num-1,limit&&i==up_bound);
            }else
            cnt+=dfs(len-1,num,limit&&i==up_bound);
        }
        if(!limit)dp[len][num]=cnt; //注意这里需要不为limit,不然后面会有限制
        return cnt;
    }
    ll solve(ll x){
        long long k=0;
        long long g1=1;
        while(x){
        digit[++k]=x%10;
        x/=10;
        }
        dfs(k,3,true);
    }
    int main(){
        long long i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
        //freopen("in.txt","r",stdin);
        long long T;
        ll g1,g2,g3,g4;
        cin >> T;
        while(T--){
        cin >> g1>> g2;
        g3=solve(g1-1);
        g4=solve(g2);
        cout << g4-g3<< endl;
        }
        return 0;
    }
    

    3.codeforces55d(挖坑

  7. 想了好一会以为对的做法其实还是太年轻。

  8. 开始想dp[i][j]表示i位,可以mod(j),这里j为二进制表示0~9的集合,的数量,

    1. 这里出现一个问题,如果之前为1x,那么dp[1][3]为(10、11、12、15)4个数字,二

    2. 如果前面的数字变了,其实就也许可以比如104mod4这样的出现了,也就是说前面的数字改变了,模数很可能是改了的。

猜你喜欢

转载自blog.csdn.net/qq_36124802/article/details/82804451