CF2115E

思路

对于完全背包问题,在 极大的时候,会选很多性价比最高的物品。令 最大的物品,非性价比最高的物品至多选 件,因为如果存在两个时刻,非性价比最高的物品选的体积模 相同,那么可以把这一部分全部替换为

所以对于 的情况,只需要做模 的同余最长路,即 P9140,转两圈即可。具体就是,当加入 时, 连权值为 的边。

现在是 DAG,只能钦定一个 ,再记录有没有到过 这个点,还要求不能路过性价比大于 的点,否则会出现正权环。复杂度

对于 的部分,直接暴力 dp

查询只需要枚举钦定的是什么,复杂度

code

int n,m,q;
int c[maxn],w[maxn];
vector<int> e[maxn];
int f[maxn][maxn*maxn];
int g[maxn][maxn][maxn][2];
void work(){
	n=read();m=read();
	for(int i=1;i<=n;i++)c[i]=read(),w[i]=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read();
		e[u].pb(v);
	}
	for(int u=1;u<=n;u++){
		for(int i=c[u];i<maxn*maxn;i++)f[u][i]=max(f[u][i],f[u][i-c[u]]+w[u]);
		for(int v:e[u]){
			for(int i=0;i<maxn*maxn;i++)f[v][i]=max(f[v][i],f[u][i]);
		}
	}
	for(int i=1;i<=n;i++){
		for(int u=1;u<=n;u++){
			for(int j=0;j<c[i];j++)g[i][u][j][1]=-inf;
		}
		if(i==1){
			for(int j=0;j<c[i];j++)g[i][1][j][1]=0;
		}
		for(int u=1;u<=n;u++)if(w[u]*c[i]<=w[i]*c[u]){
			int gg=__gcd(c[i],c[u]);
			for(int s=0;s<gg;s++){
				for(int j=s,t=0,jj;t<2;j=jj,t+=(j==s)){
					jj=(j+c[u])%c[i];
					g[i][u][jj][0]=max(g[i][u][jj][0],g[i][u][j][0]+w[u]-(j+c[u])/c[i]*w[i]);
					g[i][u][jj][1]=max(g[i][u][jj][1],g[i][u][j][1]+w[u]-(j+c[u])/c[i]*w[i]);
				}
			}
			for(int v:e[u])if(w[v]*c[i]<=w[i]*c[v]){
				for(int j=0;j<c[i];j++){
					g[i][v][j][i==v]=max(g[i][v][j][i==v],g[i][u][j][0]);
					g[i][v][j][1]=max(g[i][v][j][1],g[i][u][j][1]);
				}
			}
		}
	}
	q=read();
	while(q--){
		int u=read(),v=read();
		if(v<maxn*maxn)printf("%lld\n",f[u][v]);
		else{
			int ans=0;
			for(int i=1;i<=n;i++)if(w[u]*c[i]<=w[i]*c[u]){
				ans=max(ans,g[i][u][v%c[i]][1]+v/c[i]*w[i]);
			}
			printf("%lld\n",ans);
		}
	}
}