样例#3 不过求调
查看原帖
样例#3 不过求调
565265
I_will_AKIOI我心依旧楼主2024/11/19 21:05

我想先打一个 O(n2m)O(n^2m) 的暴力,然后上一个线段树,但是暴力打了不过样例#3,求调。

状态是设 fi,jf_{i,j} 表示当前已经删了 i1i-1 个数,k=jk=j 的最小花费,gi,jg_{i,j} 表示方案数。

#include<bits/stdc++.h>
#define int long long
#define mod 1000000007
#pragma GCC optimize("O3")
using namespace std;
struct Data{int l,r,minn,sum;};
int n,m,ans,tot;
void solve()
{
	cin>>n>>m;
	vector<int>a(n+5,0),b(m+5,0);
	vector<vector<int> >f(n+5),g(n+5);
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=m;i++) cin>>b[i];
	for(int i=0;i<=n+4;i++) f[i].resize(m+5,1e18),g[i].resize(m+5,0);
	f[1][1]=0,g[1][1]=1;
	for(int i=1;i<=n+1;i++)
	{
		for(int j=1;j<=m;j++)//操作2的转移
		{
			int sum=0,p=i;
			for(int k=i-1;k>=1;k--)//找到最长能删除的长度
			{
				sum+=a[k];
				if(sum>b[j]) break;
				p=k;
			}
			for(int k=i-1;k>=p;k--) f[i][j]=min(f[i][j],f[k][j]+m-j);
			for(int k=i-1;k>=p;k--) if(f[k][j]+m-j==f[i][j]) g[i][j]=(g[i][j]+g[k][j])%mod;
		}
		int minn=1e18,sum=0;
		if(i!=n+1)//不能在a为空转移
		{
			for(int j=1;j<=m;j++)//操作1的转移
			{
				if(minn==f[i][j]) g[i][j]=(g[i][j]+sum)%mod,sum=(sum+g[i][j])%mod;//和当前最小值相同
				else if(minn<f[i][j]) g[i][j]=sum;//最小值更优
				else sum=g[i][j];//当前值更优
				minn=min(minn,f[i][j]);
				f[i][j]=min(f[i][j],minn);
			}
		}
	}
	ans=1e18;
	tot=0;
	for(int i=1;i<=m;i++) ans=min(ans,f[n+1][i]);//计算最小花费和方案数
	for(int i=1;i<=m;i++) if(f[n+1][i]==ans) tot=(tot+g[n+1][i])%mod;
	if(ans==1e18) cout<<-1<<"\n";
	else cout<<ans<<" "<<tot<<"\n";
	return;
}
signed main()
{
	ios::sync_with_stdio(0);
	int t;
	cin>>t;
	while(t--) solve();
	return 0;
}
2024/11/19 21:05
加载中...