1. 程式人生 > >BZOJ1799-[Ahoi2009]self 同類分佈

BZOJ1799-[Ahoi2009]self 同類分佈


題解:
我們統計前面的模數?
按照平常的思維,會定義dp[i][j][k]為當前掃到前i位,數位和為j,數字取模數位和後為k,跑一遍Rdp再跑一遍L1dp
然而跑一遍是不行的…因為前面的取模和後面的取模沒有關係,之間是不能轉移的….
那該如何思考?
所以這道題需要列舉數位和(也就是模數),對每個數位和都跑一次dfs,因為數字在longlong範圍內,數位和最大隻會有918=162,是可過的。
Code:

#include<bits/stdc++.h> 
#define ll long long
using namespace std; ll f[21][200][200][2],a,b; int n,sum=9*18+1,dight[20]; ll find(ll x,int mod) { if(!x)return 0; memset(f,0,sizeof(f)); int num=0; while(x) { dight[++num]=x%10; x/=10; } f[num+1][0][0][0]=1; for(int i=num+1;i>1;i--) for(int j=0;j<=mod
;j++) for(int k=0;k<mod;k++) { if(!f[i][j][k][0]&&!f[i][j][k][1])continue; for(int p=0;p<=9;p++) { if(p<dight[i-1]&&(j+p<=mod))f[i-1][j+p][(10*k+p)%mod][1]+=f[i][j][k][0];else if
(p==dight[i-1]&&(j+p<=mod))f[i-1][j+p][(10*k+p)%mod][0]+=f[i][j][k][0]; if(f[i][j][k][1]&&(j+p<=mod)) f[i-1][j+p][(10*k+p)%mod][1]+=f[i][j][k][1]; } } return f[1][mod][0][0]+f[1][mod][0][1]; } int main() { scanf("%lld%lld",&a,&b); ll ans=0; for(int i=1;i<sum;i++) ans+=find(b,i)-find(a-1,i); printf("%lld\n",ans); return 0; }