Luogu P2657 [SCOI2009]windy数

题目
首先我们可以非常轻松地预处理出\(f_{i,j}\)表示一个最高位为\(i\)位且该位为\(j\)的windy数的个数。
然后我们可以利用经典容斥把答案变成求\([1,x]\)的windy数个数。
\(x\)\(len\)位,从低到高位分别是\(a_1,\cdots,a_{len}\)
首先我们把位数小于\(len\)的答案求出。
然后求出位数等于\(len\)且首位小于\(a_{len}\)的答案。
然后我们从大到小枚举\(len\sim i-1\)位相等,\(i\)位不等,枚举第\(i\)位从\(1\)\(a_{i}-1\),如果第\(i\)位的数\(j\)\(a_{i+1}\)差的绝对值\(\ge2\),那么这里的答案就是\(f_{i,j}\)

#include<bits/stdc++.h>
using namespace std;
int f[11][11],a[11];
int abs(int a){return a<0? -a:a;}
void init()
{
    for(int i=0;i<=9;++i) f[1][i]=1;
    for(int i=2,j,k;i<=10;++i) for(j=0;j<=9;++j) for(k=0;k<=9;++k) if(abs(j-k)>=2) f[i][j]+=f[i-1][k];
}
int cal(int x)
{
    int i,j,len=0,ans=0;
    while(x) a[++len]=x%10,x/=10;
    for(i=1;i<len;++i) for(j=1;j<=9;++j) ans+=f[i][j];
    for(i=1;i<a[len];++i) ans+=f[len][i];
    for(i=len-1;i;--i)
    {
	for(j=0;j<a[i];++j) if(abs(j-a[i+1])>=2) ans+=f[i][j];
	if(abs(a[i+1]-a[i])<2) break;
    }
    return ans;
}
int main(){int a,b;init();cin>>a>>b;cout<<cal(b+1)-cal(a);}
posted @ 2019-10-23 21:31  Shiina_Mashiro  阅读(98)  评论(0编辑  收藏  举报