云顶之弈

题意:游戏的过程可以被简化成这样一个模型:

发牌员会发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;
}
posted @ 2019-11-07 17:33  kmxzc  阅读(232)  评论(0)    收藏  举报