[题解]P9129 [USACO23FEB] Piling Papers G

P9129 [USACO23FEB] Piling Papers G

不怎么常规的数位 DP。

下文中我们规定一个数的最高位为第 \(1\) 位。

下标和值域的限制都可以差分转成前缀求解。

因此我们需要解决的转化为:对于 \(a\) 的某个前缀,其 \(\le t\) 的方案数是多少?

先考虑只有 \(x\to\overline{xa_i}\)\(x\to x\) 的情况,我们可以直接定义 \(f[i][j][0/1/2]\) 表示从 \(a[1\sim i]\) 中取出 \(j\) 个数字进行操作,使得到的值与 \(t\) 长为 \(j\) 后缀的大小关系为小于/等于/大于的方案数。转移是容易的。

如果加上 \(x\to\overline{a_ix}\) 的情况,前插会使后面的元素全部错位,无法递推。

这启发我们为 \(t\) 的两侧都添加限制,即用 \(f[i][l][r][0/1/2]\) 来表示从 \(a[1\sim i]\) 中取出 \(r-l+1\) 个数字进行操作,使得到的值与 \(t[l\sim r]\) 的大小关系为小于/等于/大于的方案数。

对于 \(f[i][x][y][*]\) 的转移,分三种情况讨论即可:

  • 不使用 \(a[i]\)

    • \(f[i][x][y][*]\gets f[i-1][x][y][*]\)
  • \(a[i]\) 前插。

    • \(a[i]>t[x]\),则 \(f[i][x][y][2]\gets \sum_k f[i-1][x+1][y][k]\)

    • \(a[i]=t[x]\),则 \(f[i][x][y][*]\gets f[i-1][x+1][y][*]\)

    • \(a[i]<t[x]\),则 \(f[i][x][y][0]\gets \sum_k f[i-1][x+1][y][k]\)

  • \(a[i]\) 后插。

    • \(f[i][x][y][0]\gets f[i-1][x][y-1][0]\)

    • \(f[i][x][y][sta]\gets f[i-1][x][y-1][1]\)\(sta\) 表示 \(a[i]\)\(t[y]\) 的大小关系)。

    • \(f[i][x][y][2]\gets f[i-1][x][y-1][2]\)

时间复杂度 \(O(qn\log^2 V)\),其中 \(V\)\(A,B\) 同阶,但实际上我们可以预处理出每个区间的答案,这样优化到了 \(O(n^2\log^2 V+q)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=305,M=20,P=1e9+7;
int n,A,B,a[N],q,l,r,ansA[N][N],ansB[N][N],t[N],m,f[M][M][3];
inline int get(int a,int b){return a<b?0:a==b?1:2;}
inline void add(int &x,int y){x+=y;if(x>=P) x-=P;}
inline void init(int x){
	m=0;
	while(x) t[++m]=x%10,x/=10;
	reverse(t+1,t+1+m);
}
inline void solve(int x,int ans[N][N]){
	init(x);
	for(int i=1;i<=n;i++){
		memset(f,0,sizeof f);
		for(int j=i;j<=n;j++){
			for(int x=1;x<=m;x++){
				for(int y=m;y>x;y--){//类似01背包的空间优化 需要倒序枚举
					if(a[j]>t[x])       for(int k=0;k<3;k++) add(f[x][y][2],f[x+1][y][k]);
					else if(a[j]==t[x]) for(int k=0;k<3;k++) add(f[x][y][k],f[x+1][y][k]);
					else                for(int k=0;k<3;k++) add(f[x][y][0],f[x+1][y][k]);
					add(f[x][y][0],f[x][y-1][0]);
					add(f[x][y][get(a[j],t[y])],f[x][y-1][1]);
					add(f[x][y][2],f[x][y-1][2]);
				}
			}
			for(int x=1;x<=m;x++) add(f[x][x][get(a[j],t[x])],2);//处理边界 
			for(int k=1;k<=m;k++){
				add(ans[i][j],f[k][m][0]);
				add(ans[i][j],f[k][m][1]);
				if(k^1) add(ans[i][j],f[k][m][2]);
			}
		}
	}
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>A>>B,A--;
	for(int i=1;i<=n;i++) cin>>a[i];
	solve(A,ansA),solve(B,ansB);
	cin>>q;
	while(q--){
		cin>>l>>r;
		cout<<(ansB[l][r]-ansA[l][r]+P)%P<<"\n";
	}
	return 0;
}
posted @ 2025-11-10 17:08  Sinktank  阅读(5)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.