zoukankan      html  css  js  c++  java
  • 数位dp初探

    我这种蒟蒻就一直不会写数位dp。。

    于是开了个坑。。

    1833: [ZJOI2010]count 数字计数

    这道被KPM大爷说是入门题。。嗯似乎找找规律然后减掉0的情况后乱搞就可以了。。(但是还是写了很久TAT

    #include<cstring>
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #define rep(i,l,r) for (int i=l;i<=r;i++)
    #define down(i,l,r) for (int i=l;i>=r;i--)
    #define clr(x,y) memset(x,y,sizeof(x))
    #define low(x) (x&(-x)) 
    #define maxn 505
    #define inf int(1e9)
    #define mm 1000000007
    #define ll long long
    using namespace std;
    ll ans[10][2];
    ll a,b,bin[18];
    ll read(){
        ll x=0,f=1; char ch=getchar();
        while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
        while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    int get(ll x){
        if (x==0) return 1;
        int ans=0; 
        while(x){ans++; x/=10;}
        return ans;
    }
    void cal(ll x,int f){
        int L,l=get(x),a; L=l;
        rep(i,0,9) ans[i][f]=(l-1)*bin[l-2];
        rep(i,1,l-2) ans[0][f]-=bin[i];
        while (l){
            a=x/bin[l-1];
            if (l==L) rep(i,1,a-1) {
                ans[i][f]+=bin[l-1];
                if (l-2>=0) rep(j,0,9) ans[j][f]+=1LL*(l-1)*bin[l-2];
            }
            if (l!=L) rep(i,0,a-1) {
                ans[i][f]+=bin[l-1];
                if (l-2>=0) rep(j,0,9) ans[j][f]+=1LL*(l-1)*bin[l-2]; 
            }
            ans[a][f]+=x%bin[l-1]+1;
            x=x%bin[l-1];
            l--;
        }
    }
    int main(){
        bin[0]=1; rep(i,1,13) bin[i]=bin[i-1]*10; 
        a=read(); b=read();
        cal(a-1,0); 
        cal(b,1);
        rep(i,0,8) printf("%lld ",ans[i][1]-ans[i][0]);
        printf("%lld
    ",ans[9][1]-ans[9][0]);
        return 0;
    } 
    View Code

    1026: [SCOI2009]windy数

    这道写个dp f[i][j]表示第i位最前一位数是j,特判一下0的情况。。

    #include<cstring>
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #define rep(i,l,r) for (int i=l;i<=r;i++)
    #define down(i,l,r) for (int i=l;i>=r;i--)
    #define clr(x,y) memset(x,y,sizeof(x))
    #define low(x) (x&(-x)) 
    #define maxn 505
    #define inf int(1e9)
    #define mm 1000000007
    #define ll long long
    using namespace std;
    int f[15][10],bin[15];
    int a,b;
    int read(){
        int x=0,f=1; char ch=getchar();
        while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
        while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    int get(ll x){
        if (x==0) return 1;
        int ans=0; 
        while(x){ans++; x/=10;}
        return ans;
    }
    int cal(int x){
        int L,l=get(x),ans=0,a,tmp=-100; L=l;
        if (l>1) ans++;//0的情况
        rep(i,1,l-1) {
            rep(j,1,9) ans+=f[i][j];
        }
        while (l){
            a=x/bin[l-1];
            if (l==L) rep(i,1,a-1) if (abs(i-tmp)>=2){
                rep(j,0,9) if (abs(i-j)>=2) ans+=f[l-1][j];
            }
            if (l!=L) rep(i,0,a-1) if (abs(i-tmp)>=2){
                rep(j,0,9) if (abs(i-j)>=2) ans+=f[l-1][j];
            }
            if (l==1) rep(i,0,a) if (abs(tmp-i)>=2) ans++;  
            if (abs(tmp-a)<2) break;
            tmp=a;
            x%=bin[l-1];
            l--;
        }
        return ans;
    }
    int main(){
        bin[0]=1; rep(i,1,9) bin[i]=bin[i-1]*10;
        a=read(); b=read();
        int l=get(b);
        rep(i,0,9) f[1][i]=1;
        rep(i,1,9) rep(j,0,9) if (f[i][j]){
            rep(k,0,9) if (abs(j-k)>=2) f[i+1][k]+=f[i][j];
        }
        printf("%d
    ",cal(b)-cal(a-1));
        return 0;
    } 
    View Code

    1072: [SCOI2007]排列perm

    为什么我一直认为这道是状压。。 f[s][i]表示当前状态是s,模数为i。然后枚举每一个数是否被选过转移就可以了。

    最后除掉相同数字个数的阶乘。

    #include<cstring>
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #define rep(i,l,r) for (int i=l;i<=r;i++)
    #define down(i,l,r) for (int i=l;i>=r;i--)
    #define clr(x,y) memset(x,y,sizeof(x))
    #define low(x) (x&(-x)) 
    #define maxn 505
    #define inf int(1e9)
    #define mm 1000000007
    #define ll long long
    using namespace std;
    int f[1050][1005];
    int n,t,l,bin[20],a[20],num[20],p[20],ans;
    char s[15];
    int read(){
        int x=0,f=1; char ch=getchar();
        while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
        while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    int main(){
        t=read();
        bin[0]=1; rep(i,1,10) bin[i]=bin[i-1]*2;
        p[0]=1; rep(i,1,10) p[i]=p[i-1]*i;
        while (t--){
            clr(f,0); clr(num,0);
            scanf("%s",s); l=strlen(s);
            int d=read();
            rep(i,0,l-1) a[i]=s[i]-'0',num[a[i]]++;
            //printf("%d
    ",bin[l]-1);
            f[0][0]=1; 
            rep(s,0,bin[l]-1) rep(j,0,d-1) if (f[s][j]){
                rep(k,0,l-1) if ((s&bin[k])==0) f[s+bin[k]][(j*10+a[k])%d]+=f[s][j];
            }
            ans=f[bin[l]-1][0];
            rep(i,0,9) if (num[i]) ans/=p[num[i]];
            printf("%d
    ",ans);
        }
        return 0;
    } 
    View Code

    2425: [HAOI2010]计数

    题目其实就是给你一些数字让你用这些数字构造一个个比给定数小的数。。

    比如说我现在这一位最高为x,那就取0~x-1(可以有前导0)为这一位然后剩下的数自由组合。

    对于这个自由组合,比如剩下有n位,这个数字还剩下有x个,那每一次就乘上C(n,x)然后n-=x。

    #include<cstring>
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cmath>
    #include<algorithm>
    #define rep(i,l,r) for (int i=l;i<=r;i++)
    #define down(i,l,r) for (int i=l;i>=r;i--)
    #define clr(x,y) memset(x,y,sizeof(x))
    #define low(x) (x&(-x)) 
    #define maxn 505
    #define inf int(1e9)
    #define mm 1000000007
    #define ll long long
    using namespace std;
    ll c[55][55],ans;
    int cnt[10],a[55];
    char s[55];
    int read(){
        int x=0,f=1; char ch=getchar();
        while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
        while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    ll cal(int n){
        ll ans=1;
        int now=n;
        rep(i,0,9) ans*=c[now][cnt[i]],now-=cnt[i];
        return ans; 
    }
    int main(){
        c[0][0]=1; 
        rep(i,1,50) {
            c[i][0]=1;
            rep(j,1,50) c[i][j]=c[i-1][j-1]+c[i-1][j];
        }
        scanf("%s",s); int l=strlen(s);
        rep(i,0,l-1) a[i+1]=s[i]-'0',cnt[a[i+1]]++;
        rep(i,1,l) {
            rep(j,0,a[i]-1) if (cnt[j]){
                cnt[j]--;
                ans+=cal(l-i);
                cnt[j]++;
            }
            cnt[a[i]]--;
        }
        printf("%lld
    ",ans);
        return 0;
    } 
    View Code

    BZOJ1799: [Ahoi2009]self 同类分布

    http://www.cnblogs.com/ctlchild/p/5126952.html

    (还有几道题目慢慢填TAT。。。

  • 相关阅读:
    reset代码
    将博客搬至CSDN
    超简单的JNI——NDK开发教程
    浅谈Backbone的defaults
    为什么NaN !== NaN
    javascript小技巧[转]
    new function()随笔
    小记js中普通function和arrow function内this的使用区别
    evernote出现“Sync failed due to unexpected problem at server side”的问题
    强迫症和拖延症患者如何应对马桶4(遨游Maxthon)“上次未关闭页面”丢失的问题
  • 原文地址:https://www.cnblogs.com/ctlchild/p/5131420.html
Copyright © 2011-2022 走看看