P9129 [USACO23FEB] Piling Papers G

前置知识

数位dp,区间dp

思路

妙妙题。

看到 求满足一定条件在 \(A,B\le10^{18}\) 之间的数,很显然会想到数位 dp。

所以按照思路,先将问题转化为求 \(1-N\) 之间的数。但是和普通的数位 dp 不同的是,我们在转移时不仅可以在后面加,也可以在前面加。好,我不会了。所以我打开了题解。

我们发现在前面加实际上也是可以实现的,套上一个区间 dp 即可。设 \(dp_{i,j,l,r,0/1/2}\) 表示用了字片 \(i\)\(j\) 拼成数的 \(l\)\(r\) 与目标在这一段的关系大于/等于/小于,转移就变得容易起来了,对于每个新加入的数放在左边或右边即可。然后来思考时间复杂度 \(O(n^2len^2)\)\(len\) 表示位数 )。完工。

#include <bits/stdc++.h>
using namespace std;
const int M=310,N=20,mod=1e9+7;
#define ll long long
int b[N],wss,n,q,a[M];
ll A,B,f[N][N][3],ans[3][M][M];
void upd(ll &x,ll y){x=(x+y)%mod;}
void cw(ll z)
{
	wss=0;
	while(z)
	{
		b[++wss]=z%10;
		z/=10;
	} 
	reverse(b+1,b+1+wss);
	return ;
} 
void dp(int lx)
{
	for(int i=n;i>=1;i--)
	{
		memset(f,0,sizeof(f));
		for(int j=i;j<=n;j++)
		{
			for(int l=1;l<wss;l++)
				for(int r=wss;r>l;r--)//注意枚举顺序
				{
					for(int k=0;k<=2;k++)
					{
						if(b[l]>a[j])upd(f[l][r][0],f[l+1][r][k]);//当前小,全部小 
						if(b[l]==a[j])upd(f[l][r][k],f[l+1][r][k]);//当前位相等,大小是后面的大小 
						if(b[l]<a[j]) upd(f[l][r][2],f[l+1][r][k]); 
					} //枚举放左边 
					if(b[r]==a[j])for(int k=0;k<=2;k++)upd(f[l][r][k],f[l][r-1][k]);//当前位相等,大小是前面的大小  
					if(b[r]<a[j]) 
					{
						upd(f[l][r][0],f[l][r-1][0]);//前面小就小
						upd(f[l][r][2],(f[l][r-1][1]+f[l][r-1][2])%mod); 
					}
					if(b[r]>a[j])
					{
						upd(f[l][r][0],(f[l][r-1][0]+f[l][r-1][1])%mod);//前面大就大 
						upd(f[l][r][2],f[l][r-1][2]);  
					}
					//枚举放右边 
				} 
			for(int l=1;l<=wss;l++)
			{
				if(b[l]>a[j])upd(f[l][l][0],2);//特殊处理,前面加和后面加一样但是两种方案
				if(b[l]==a[j])upd(f[l][l][1],2);
				if(b[l]<a[j])upd(f[l][l][2],2); 
			}
            //将所有答案先记下来
			upd(ans[lx][i][j],(f[1][wss][0]+f[1][wss][1])%mod);//位数相同的贡献 
			for(int r=1;r<wss;r++)//位数小 
				for(int k=0;k<=2;k++)upd(ans[lx][i][j],f[1][r][k]);
			//cout<<ans[lx][i][j]<<'\n';	
		}	
	}
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>A>>B;
	for(int i=1;i<=n;i++)cin>>a[i];
	cw(A-1);
	dp(0);//处理A-1
	cw(B);
	dp(1);
	cin>>q; 
	for(int i=1;i<=q;i++)
	{
		int l,r;cin>>l>>r;
		cout<<(ans[1][l][r]-ans[0][l][r]+mod)%mod<<'\n';
	}
	return 0;
} 
posted @ 2025-05-08 16:30  exCat  阅读(65)  评论(0)    收藏  举报