(數位dp)E 詭異數字
阿新 • • 發佈:2019-02-03
牛客小白月賽8真的打的自閉了,感覺一點都不小白 T_T (肯定是我太菜了,沒錯就是這樣的)
題解說這是一個非常簡單的數位dp,沒接觸過,感覺挺難的(大概這就是菜吧)
然後看懂了大佬的程式碼,敲了一下再附上了我的理解
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=20020219; const ll maxn=1e3+5; ll lim[20],len[20];//lim分別記錄每個數的最大重複次數,沒有就置大 ll a[100][100][100];//len將數存入陣列,每個位置也代表著上限 // pos pre num // 記錄著位數為pos(包括前導0,0012也算4位數),前驅是pre,前驅重複數為num的滿足條件的個數 // pos位的每一個位置的範圍都是0-9,(就是代表完整的pos位數) ll le,ri,n; ll dfs(int pos,bool limit,int pre,int num){ if(num>lim[pre]) return 0;//超過pre允許出現的最大次數,返回0 if(pos==0) return 1;// 0位返回1 if(!limit && a[pos][pre][num]!=-1) return a[pos][pre][num];//前驅不是上限,而且被更新過直接用 //如果前驅是上限,則後面上限也受到限制,不是一個完整的pos位,故不可用 int up=limit?len[pos]:9; //如果前驅達到上限,則這個位置的上限為解決數的上限 ll sum=0; for(int i=0;i<=up;++i) { sum=(sum+dfs(pos-1,limit&&i==len[pos],i,i==pre?num+1:1))%mod; } return limit?sum:a[pos][pre][num]=sum;//前驅不是上限就更新,否則直接return } ll solve(ll xx) { if(xx==-1) return 0; ll cnt=0; while(xx){ len[++cnt]=xx%10;//每一位放入陣列,cnt代表位數 xx/=10; } ll ans=0; for(int i=0;i<=len[cnt];++i){//最高位從0-len[cnt]列舉 ans=(ans+dfs(cnt-1,i==len[cnt],i,1))%mod; } return ans%mod; } int main(){ int T; scanf("%d",&T); while(T--){ fill(lim,lim+11,0xffffffff); memset(a,-1,sizeof(a)); scanf("%lld%lld%lld",&le,&ri,&n); ll xx,max_num; for(ll i=0;i<n;++i){ scanf("%lld%lld",&xx,&max_num); lim[xx]=min(lim[xx],max_num);//更新 xx最大能出現lim[xx]次 } cout<<(solve(ri)-solve(le-1)+mod)%mod<<endl; } return 0; }