题面

 

 

数位DP

考虑先记从1~9999...999(i个9)中鲳对的数量为$f_i$。

记从1~9999...999(i个9)中数位j的数量为$ff_{ij}$,然后发现所有$ff_ix$都是相等的,就只记一个。

(下面代码 pw10[i] 为 $10^i$)

 1 for(int i=1;i<=500000;i++){
 2     f[i]=f[i-1]*10%998244353;
 3     ff[i]=(ff[i-1]*10+pw10[i-1])%998244353;
 4     for(int j=0;j<10;j++)
 5         for(int k=0;k<j;k++){
 6             f[i]+=ff[i-1];
 7             f[i]%=998244353;
 8         }
 9 //    cerr<<i<<" "<<f[i]<<endl;
10 }

 

容易想到差分,记 $f(l,r)$ 为区间 $[l,r]$ 的鲳对数量,那么:$f(l,r)=f(1,r)-f(1,l-1)$,由于我们不好求 $l-1$,所以可以将 $f(1,l-1)$ 转化为 $f(1,l)-l的鲳对个数$。

 

1 while(t--){
2     cin>>l>>r;
3     printf("%lld\n",(get(r)-get(l)+getone(l)+998244353)%998244353);
4 }

 

get函数即为求$f(1,x)$的鲳对个数。

我们可以从高往低求每一位的答案。首先对于每一位$i$(假设那位上的数字是 $a_i$),可以求出$i$位后面独立的鲳对个数,即$f_{i-1}$。但由于你可以是0xxx,1xxx,2xxx……从$0\sim a_i-1$共 $a_i$ 个数,所以要乘 $a_i$,之所以不取 $a_i$ 是因为它不是完整的 1~9999...999。

接着求当前位对于后续位的贡献,因为当前位只是 $\le a_i$,所以要分 $< a_i$ 和 $= a_i$ 两种来处理。如果是 $< a_i$,那么直接枚举 $j$ 从 $0\sim a_i-1$,所有小于 $j$ 的数($j$ 个)都可以提供 $ff_{i-1}$ 的贡献。当等于 $a_i$ 的时候,因为我们一直不知道剩余位数里有多少个指定数字,所以先记到一个标记数组里,每一次当下一个 $< a_j$ 的位数出现的时候加上 < 它数字的数量个 $ff_{j-1}$就行了,$< a_j$的非负整数共 $a_j$ 个(因为有0),所以还要乘以 $a_j$

处理完后续位的贡献,接着还要处理当前位与前面位的贡献。

如果当前位 $< a_i$,那么前面 > 这个数的就会产生个数 $\times$ 后面数字数量(即 $10^{i-1}$)个贡献。

如果当前位 $= a_i$,那么前面 > 这个数的就会产生个数 $\times$ 后面数字数量(即后面数字所组成的数)个贡献。

最后把当前位加入为前面的标记数组里就行了

代码因为string第一位是最高位,所以求的时候是从0枚举到$s.size()-1$的,马蜂有点奇怪,常数还大,建议不看。
真的要看吗?
#include<bits/stdc++.h>
using namespace std;
namespace estidi{
	long long now[13],f[500003],ff[500003],last[500003],pw10[500003];
	long long getone(string s){
		int ans=0;
		for(int i=0;i<s.size();i++){
			now[s[i]-'0']++;
			for(int j=s[i]-'0'+1;j<10;j++){
				ans+=now[j];
				ans%=998244353;
			}
		}
		for(int i=0;i<10;i++)
			now[i]=0;
		return ans;
	}
	long long get(string s){
		long long ans=0;
		last[s.size()]=0;
		for(int i=s.size()-1;i>=0;i--)//预处理后面数字所组成的数
			last[i]=(last[i+1]+pw10[s.size()-i-1]*(s[i]-'0'))%998244353;
		for(int i=0;i<s.size();i++){
			ans+=f[s.size()-i-1]*(s[i]-'0');
			ans%=998244353;
			for(int j=0;j<s[i]-'0';j++){
				ans+=ff[s.size()-i-1]*j%998244353;
				ans%=998244353;
			}
			for(int j=0;j<10;j++){
				ans+=ff[s.size()-i-1]*now[j]%998244353*(s[i]-'0')%998244353*j%998244353;
				ans%=998244353;
			}
			for(int j=0;j<s[i]-'0';j++)
				for(int k=j+1;k<10;k++)
					ans+=now[k]*pw10[s.size()-i-1];
			for(int k=s[i]-'0'+1;k<10;k++)
				ans+=now[k]*(last[i+1]+1);
			now[s[i]-'0']++;
		}
//		cout<<s<<":"<<ans<<endl;
		for(int i=0;i<10;i++)
			now[i]=0;
		return ans;
	}
	int main(){
//		freopen("pair.in","r",stdin);
//		freopen("pair.out","w",stdout);
		pw10[0]=1;
		for(int i=1;i<=500000;i++)
			pw10[i]=pw10[i-1]*10%998244353;
		int t,tc;
		string l,r;
		scanf("%d%d",&t,&tc);
		for(int i=1;i<=500000;i++){
			f[i]=f[i-1]*10%998244353;
			ff[i]=(ff[i-1]*10+pw10[i-1])%998244353;
			for(int j=0;j<10;j++)
				for(int k=0;k<j;k++){
					f[i]+=ff[i-1];
					f[i]%=998244353;
				}
//			cerr<<i<<" "<<f[i]<<endl;
		}
		while(t--){
			cin>>l>>r;
			printf("%lld\n",(get(r)-get(l)+getone(l)+998244353)%998244353);
		}
		return 0;
	}
}
int main(){
	estidi::main();
	return 0;
}
posted on 2024-07-10 19:06  123asdf123  阅读(26)  评论(0编辑  收藏  举报