1. 程式人生 > >數位DP專題(持續填坑中)

數位DP專題(持續填坑中)

www code 記錄 技術分享 hid sizeof tdi div mem

洛谷P3107題面

相對較為模板化的代碼 f[i][j][bo1][bo2]記錄到第i位,數字num出現了x次(j初始為20,若當前數字不為num,j++;否則j--;最後只要記錄j<=20的總和)bo1和bo2就很簡單了,上界和前導零

技術分享圖片
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
#define int long long
string l,r;
int f[25][55][2][2],kkk[20
]; inline int DP(int le,int num1,int num2) { int re=0,i,bo1,bo2,j,k,bo,pp; memset(f,0,sizeof f); f[0][20][1][1]=1; //bo1:上界 bo2:前導零 for(i=0;i<le;i++) { for(j=0;j<=50;j++) { for(bo1=0;bo1<2;bo1++) { for(bo2=0;bo2<2;bo2++) {
if(f[i][j][bo1][bo2]==0)continue; for(k=0;k<=9;k++) { if((num2!=-1&&(k!=0||!bo2)&&k!=num1&&k!=num2)||(bo1&&k>kkk[i]))continue; pp=j; if(!bo2||k!=0) {
if(num2==-1) { if(k==num1)pp--;else pp++; } else { if(k==num1)pp--;else if(k==num2)pp++; } }f[i+1][pp][bo1&(k==kkk[i])][bo2&(k==0)]+=f[i][j][bo1][bo2]; } } } } } if(num2==-1) { for(i=0;i<=20;i++)for(j=0;j<2;j++)re+=f[le][i][j][0]; }else for(i=0;i<2;i++)re+=f[le][20][i][0]; return re; } inline int solve(string s) { int re=0,i,j,le=s.size(); for(i=0;i<le;i++) kkk[i]=s[i]-0; for(i=0;i<=9;i++) re+=DP(le,i,-1); for(i=0;i<9;i++) { for(j=i+1;j<=9;j++)re-=DP(le,i,j); }return re; } signed main() { int i; cin>>l>>r; for(i=l.size()-1;i>=0;i--) { if(l[i]==0)l[i]=9;else {l[i]--;break;} }printf("%lld\n",solve(r)-solve(l)); }
View Code

數位DP專題(持續填坑中)