云顶之弈
题意:游戏的过程可以被简化成这样一个模型:
发牌员会发n轮牌给玩家,每一轮,玩家会被发恰好5张卡牌到手上,玩家可以选择留下其中任意的若干张,然后把其他的卡牌扔掉。卡牌的编号是从1——n的,有每一种卡牌保证恰好只有9张或0张。
这个过程中,一旦玩家手中的某一种卡牌达到9张,那么这9张一样的卡牌将合成一个三星卡牌。
玩家手上的卡牌唯一的限制是:任意时刻,玩家手上的非三星卡牌不能超过m种(注意,是种,不是张)。
现在的问题是: HVX 假设提前看到了发牌员的计划,那么,他最多能收集多少张三星卡牌呢?
输入:第一行两个正整数n,m,表示发牌的轮数和手上非三星牌种数的限制。
接下来n行,每行5个正整数a[i][j] ,表示发牌员第i轮要发的第j张牌。
样例输入:
9 1 1 1 1 1 1 1 1 1 2 2 1 2 2 2 3 3 3 3 2 2 2 2 3 3 3 3 3 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5
样例输出:
4
对于 30%的测试数据,满足 1≤n≤10^2,m=1
对于 50%的测试数据,满足 1≤n,m≤10^3
对于 100%的测试数据,满足 1≤n,m≤2·10^4,卡牌编号≤n,保证每种牌恰 好只有 9 张或 0 张。
方法:这道题每种纸牌9张且9张全要取到才行
若我们要得到一张三星卡牌,则必须取遍所有包含这张纸牌的行
因此每张卡牌有一个作用范围,只有完全取遍这个作用范围才能得到
比如样例中1的范围【1,3】
2的范围【2,4】
把它们看成数轴上的线段
任意时刻,手中牌不超过m张——>任意位置,线段重叠部分不超过m条
当m=1时,就是贪心的经典问题,取最多的线段使得线段不重叠覆盖,见洛谷P1803
做法:按右端点排序,让左端点尽可能靠前,对后面的线段有更多的决策包容性
本题做法同理,先按右端点排序,再用线段树维护区间
比如遇到一条线段,查询左端点到右端点的区间最大值是否小于m
可行则对该线段区间加1,ans++
但注意的是:1.本题卡牌有可能是0张,需去除
2.同一行同时取,上面应改为“查询[l,r)的区间最大值是否小于m”
code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=20005;
struct Tree{
int l,r,mx,lazy;
}t[maxn*4];
struct node{
int x,y;
bool operator <(const node&b) const{
if(y!=b.y) return y<b.y;
return x<b.x;
}
}a[maxn];
int n,m,ans=0,N;
int vis[maxn];
int read(){
int x=0,f=1; char c=getchar();
while(c>'9'||c<'0'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+c-'0';
c=getchar();
}
return x*f;
}
void build(int r,int x,int y){
t[r].l=x; t[r].r=y;
if(x==y){
t[r].mx=t[r].lazy=0;
return;
}
int mid=(x+y)>>1;
build(r*2,x,mid); build(r*2+1,mid+1,y);
}
void updata(int r){
t[r].mx=max(t[r*2].mx,t[r*2+1].mx);
}
void pushdown(int r){
t[r*2].mx+=t[r].lazy;
t[r*2+1].mx+=t[r].lazy;
t[r*2].lazy+=t[r].lazy;
t[r*2+1].lazy+=t[r].lazy;
t[r].lazy=0;
}
void change(int r,int x,int y){
if(x<=t[r].l&&t[r].r<=y){
t[r].mx++;
t[r].lazy++;
return;
}
if(t[r].lazy) pushdown(r);
int mid=(t[r].l+t[r].r)>>1;
if(x<=mid) change(r*2,x,y);
if(y>mid) change(r*2+1,x,y);
updata(r);
}
int ask(int r,int x,int y){
if(x<=t[r].l&&t[r].r<=y) return t[r].mx;
if(t[r].lazy) pushdown(r);
int mid=(t[r].l+t[r].r)>>1,ans=0;
if(x<=mid) ans=max(ans,ask(r*2,x,y));
if(y>mid) ans=max(ans,ask(r*2+1,x,y));
return ans;
}
int main(){
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
n=read(); m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=5;j++){
int x=read();
N=max(N,x);
if(vis[x]==0) a[x].x=i;
vis[x]++;
if(vis[x]==9) a[x].y=i;
}
}
build(1,1,n);
sort(a+1,a+1+N);
int pos=1;
while(!a[pos].x) pos++;
for(int i=pos;i<=N;i++){
if(ask(1,a[i].x,a[i].y-1)<m){
ans++;
change(1,a[i].x,a[i].y-1);
}
}
printf("%d\n",ans);
fclose(stdin);
fclose(stdout);
return 0;
}

浙公网安备 33010602011771号