题解 P9818 游戏王
首先发现对于
考虑如何朴素地求出答案,设
然后你发现这个东西本质是个背包,把物品塞进去的顺序是没有影响的,所以直接分治,每次求出跨过当前分治中心的询问的答案,合并左子区间的后缀和右子区间的前缀即可。时间复杂度
代码:
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops")
#define ALL(v) v.begin(),v.end()
#define For(i,_) for(int i=0,i##end=_;i<i##end;++i) // [0,_)
#define FOR(i,_,__) for(int i=_,i##end=__;i<i##end;++i) // [_,__)
#define Rep(i,_) for(int i=(_)-1;i>=0;--i) // [0,_)
#define REP(i,_,__) for(int i=(__)-1,i##end=_;i>=i##end;--i) // [_,__)
typedef long long ll;
typedef unsigned long long ull;
#define V vector
#define pb push_back
#define pf push_front
#define qb pop_back
#define qf pop_front
#define eb emplace_back
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
#define fi first
#define se second
const int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}},inf=0x3f3f3f3f,mod=1e9+7;
const ll infl=0x3f3f3f3f3f3f3f3fll;
template<class T>inline bool ckmin(T &x,const T &y){return x>y?x=y,1:0;}
template<class T>inline bool ckmax(T &x,const T &y){return x<y?x=y,1:0;}
int init=[](){return cin.tie(nullptr)->sync_with_stdio(false),0;}();
int main(){
int t_case=1;
// scanf("%d",&t_case);
while(t_case--){
int m,n;
scanf("%d%d",&n,&m);
V<int>id(m+1);
id[0]=-1;
FOR(i,1,m+1){
int j=m/(m/i);
FOR(k,i,j+1)id[k]=id[i-1]+1;
i=j;
}
V<int>can(id[m]+1);
V<V<int>>mul(id[m]+1);
FOR(i,1,m+1){
int div=m/i,j=m/div;
assert(id[div]==id[m/j]);
can[id[i]]=id[div];
mul[id[i]].resize(div+1);
For(k,div+1){
assert(id[i*k]==id[j*k]);
mul[id[i]][k]=id[i*k];
}
i=j;
}
V<V<pii>>b(n);
for(auto &i:b){
int x;
scanf("%d",&x);
i.resize(x);
for(pii &j:i)scanf("%d%d",&j.fi,&j.se);
}
int t;
scanf("%d",&t);
V<int>ans(t);
V<pii>q(t);
for(pii &i:q)scanf("%d%d",&i.fi,&i.se),--i.fi,--i.se;
V<V<int>>f(n,V<int>(id[m]+1));
function<void(int,int,const V<int>&,int)>solve=[&](int l,int r,const V<int> &a,int k){
if(a.size()){
if(l==r){
int mx=0;
for(pii &i:b[l])ckmax(mx,i.fi);
for(int i:a)ans[i]=mx;
}
else{
int mid=l+r>>1,ql=mid+1,qr=mid;
V<int>al,_a,ar;
for(int i:a){
if(q[i].se<=mid)al.pb(i);
else if(q[i].fi>mid)ar.pb(i);
else _a.pb(i),ckmin(ql,q[i].fi),ckmax(qr,q[i].se);
}
solve(l,mid,al,-ql-1),solve(mid+1,r,ar,qr+1);
for(int i:_a)For(j,id[m]+1)ckmax(ans[i],f[q[i].fi][j]+f[q[i].se][can[j]]);
}
}
if(k<0){
REP(i,-k-1,r+1){
if(i==r){
fill(ALL(f[i]),0);
for(pii &j:b[i])ckmax(f[i][id[j.se]],j.fi);
}
else{
f[i]=f[i+1];
for(pii &j:b[i])For(k,can[id[j.se]]+1)ckmax(f[i][mul[k][j.se]],f[i+1][k]+j.fi);
}
For(j,id[m])ckmax(f[i][j+1],f[i][j]);
}
}
if(k>0){
FOR(i,l,k){
if(i==l){
fill(ALL(f[i]),0);
for(pii &j:b[i])ckmax(f[i][id[j.se]],j.fi);
}
else{
f[i]=f[i-1];
for(pii &j:b[i])For(k,can[id[j.se]]+1)ckmax(f[i][mul[k][j.se]],f[i-1][k]+j.fi);
}
For(j,id[m])ckmax(f[i][j+1],f[i][j]);
}
}
};
V<int>tmp(t);
iota(ALL(tmp),0);
solve(0,n-1,tmp,0);
for(int i:ans)printf("%d\n",i);
}
return 0;
}