专栏文章
题解:P13085 [SCOI2009] windy 数(加强版)
P13085题解参与者 10已保存评论 14
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 14 条
- 当前快照
- 1 份
- 快照标识符
- @miozdiqt
- 此快照首次捕获于
- 2025/12/03 03:38 3 个月前
- 此快照最后确认于
- 2025/12/03 03:38 3 个月前
由于 范围较大,直接搜索肯定是不行的,考虑数位 dp。为方便,以下“第 位”均表示从高位开始的第 位(如最高位为“第一位”)。
令 表示 位且以最高位为数字 的 windy 数的个数。显然 可以通过枚举第二位的数字得到:,初始状态为 。
接下来考虑如何计算 到 之间的 windy 数的个数。我们可以把答案拆成两个部分:小于等于 的 windy 数个数与小于 的 windy 数个数之差。我们发现这两部分是相似的(小于 即为小于等于 ),只需要考虑如何计算小于等于某个数的 windy 数个数。
假设我们要求小于等于一个数 的 windy 数个数,设其为 位,其第 位表示为 。首先考虑位数比 小的数中有多少个 windy 数:。接着我们考虑有 位但首位小于 的 windy 数:。
最后考虑 位且首位为 的 windy 数,这时我们需要考虑第二位的取值(因为第二位不能随便取,不能使用 来计算个数)。类似上面的,枚举第二位小于 的(且小于等于 ):,然后考虑第二位为 (如果 和 满足 windy 数的标准),枚举第三位的取值……
总的来说,如果 的前 位均满足 windy 数的性质(相邻两位之差大于等于 ),那么小于等于 的 windy 数个数为:
计算 的时间复杂度为 ,计算小于等于某个数的 windy 数个数的时间复杂度为 (其中 为数字个数即 , 为数字位数),空间复杂度为 。
代码如下,仅供参考:
CPP#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
ull f[20][10],power[20];
void init() {
power[0]=1;
for(int i=1;i<=19;i++) power[i]=power[i-1]*10;
for(int i=0;i<=9;i++) f[1][i]=1;
for(int i=2;i<=19;i++)
for(int j=0;j<=9;j++)
for(int k=0;k<=9;k++)
if(abs(j-k)>=2)
f[i][j]+=f[i-1][k];
return ;
}
ull solve(ull x) {
int w=0,y,pre;
ull ans=0;
while(power[w]<=x) w++;
for(int i=1;i<w;i++)
for(int j=1;j<=9;j++)
ans+=f[i][j];
y=x/power[w-1];
for(int j=1;j<y;j++) ans+=f[w][j];
pre=y,x%=power[w-1];
for(int i=w-1;i>=1;i--) {
y=x/power[i-1];
for(int j=0;j<y;j++)
if(abs(j-pre)>=2)
ans+=f[i][j];
if(abs(pre-y)<2) break;
pre=y,x%=power[i-1];
}
return ans;
}
int main() {
ull a,b;
cin>>a>>b;
init();
cout<<solve(b+1)-solve(a)<<endl;
return 0;
}
相关推荐
评论
共 14 条评论,欢迎与作者交流。
正在加载评论...