A.
解
注意,每种颜色仅出现一次。
因此树状数组维护所有操作的左右端点, \(答案=目前已完成的操作数-[1,当前操作左端点-1]中的右端点个数-[当前操作右端点+1,n]中的左端点个数\) 。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=100003;
int n,Q,tot;
struct BIT{
int t[maxn];
BIT(){memset(t,0,sizeof(t));}
void add(int pos,int k){while(pos<=n)t[pos]+=k,pos+=pos&-pos;}
int query(int pos){int ret=0;while(pos)ret+=t[pos],pos-=pos&-pos;return ret;}
int query(int l,int r){return l<=r?query(r)-query(l-1):0;}
}treel,treer;
int main(){
scanf("%d%d",&n,&Q);
while(Q--){
int mo,l,r;
scanf("%d%d%d",&mo,&l,&r);
if(mo==1){
treel.add(l,1);
treer.add(r,1);
tot++;
}
else{
printf("%d\n",tot-treer.query(1,l-1)-treel.query(r+1,n));
}
}
return 0;
}
B.
解
直接背包,每次转移维护前 \(k\) 大的值。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxk=53,maxv=5003,maxn=203;
int k,v,n,V[maxn],A[maxn];
struct T{
int a[maxk];
T(){memset(a,0,sizeof(a));}
T merge(const T &t,int val){
T ret;
int i=1,j=1;
for(;i<=*a&&j<=*t.a&&*ret.a<k;){
if(a[i]>t.a[j]+val){
ret.a[++*ret.a]=a[i];
i++;
}
else{
ret.a[++*ret.a]=t.a[j]+val;
j++;
}
}
while(i<=*a&&*ret.a<k){
ret.a[++*ret.a]=a[i];
i++;
}
while(j<=*t.a&&*ret.a<k){
ret.a[++*ret.a]=t.a[j]+val;
j++;
}
return ret;
}
}dp[maxv];
int main(){
scanf("%d%d%d",&k,&v,&n);
for(int i=1;i<=n;i++)scanf("%d%d",V+i,A+i);
dp[0].a[++*dp[0].a]=0;
for(int i=1;i<=n;i++){
for(int j=v;j>=V[i];j--){
dp[j]=dp[j].merge(dp[j-V[i]],A[i]);
}
}
int ans=0;
for(int i=1;i<=k;i++)ans+=dp[v].a[i];
printf("%d\n",ans);
return 0;
}
C.
解
如果你只设一个dp数组,这道题会变得比较困难
设 \(dp1[i][j]\) 表示拿到前 \(i\) 种物品施 \(j\) 次魔法所需最小成本, \(dp2[i][j]\) 表示拿到第 \(i\) 种物品施 \(j\) 次魔法所需最小成本, \(dp[i][j]\) 表示花 \(i\) 个金币施 \(j\) 次魔法所能获得的最大利润。
转移见下。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1003,INF=1050000000;
int n,m,V,K,a[maxn],b[maxn],dp1[maxn][maxn],dp2[maxn][maxn],dp[maxn][maxn];
vector<vector<int> > h[maxn];
int main(){
scanf("%d%d%d%d",&n,&m,&V,&K);
for(int i=1;i<=n;i++)scanf("%d%d",a+i,b+i);
for(int i=1;i<=m;i++){
int x,k;
scanf("%d%d",&x,&k);
h[x].push_back(vector<int>(k));
for(int j=0;j<k;j++)scanf("%d",&h[x].back()[j]);
}
for(int i=1;i<=n;i++){
dp2[i][0]=a[i];
for(int l=1;l<=K;l++){
dp2[i][l]=INF;
}
}
for(int l=1;l<=K;l++){
for(int i=1;i<=n;i++){
for(auto j:h[i]){
for(int p=0;p<l;p++){
for(int k=1;k<=int(j.size());k++){
dp1[k][p]=INF;
for(int q=0;q<=p;q++){
dp1[k][p]=min(dp1[k][p],dp1[k-1][p-q]+dp2[j[k-1]][q]);
}
}
}
dp2[i][l]=min(dp2[i][l],dp1[j.size()][l-1]);
}
}
}
for(int j=0;j<=K;j++){
for(int k=1;k<=n;k++){
for(int l=0;l<=j;l++){
for(int i=dp2[k][l];i<=V;i++){
dp[i][j]=max(dp[i][j],dp[i-dp2[k][l]][j-l]-dp2[k][l]+b[k]);
}
}
}
}
printf("%d\n",dp[V][K]);
return 0;
}