zoukankan      html  css  js  c++  java
  • fjwc2019 D2T2 定价 (栈+set+贪心)

    #182. 「2019冬令营提高组」定价

    先瞄下数据范围

    对于所有数据,1n1000,1≤m≤10^91≤q≤500000 。 extbf{2 操作的个数不超过 1000。}

    $10^9$位,看起来挺吓人,咋维护每个可以为1的位鸭?

    再仔细看看,$q<=500000$,最多500000次操作,那么显然是对每一列,开个动态开点线段树或者平衡树维护。

    本题对数据结构要求不高,于是我们可以快捷地用set代替辣

    接下来我们考虑如何求出价格和的最小值

    2 操作的个数不超过 1000。

    这告诉我们可以愉快地在O(nlogn)内解决

    从左到右一列列扫过去........考虑贪心

    切一段ppt

    我们先总结一下贪心的时候在干啥。

    假设我们上一行有若干位为1,那么对于下一行,我们需要找到最高的为1位,满足这一行这位不能再为1了,我们就需要选取在这个位置之前的一个可以变成1的0,把它变成1,并把后面的位置全变成0。

    直接用bitset维护可以获得部分分。

    我们考虑使用一个栈维护当前的1,假设我们能找到最高的不能继续为1的位,我们就可以从这一位开始依次遍历前面的1,找到这个1之前第一个可以变成1的位置,如果这个位置在下一个1之前就是答案。

    举个栗子

    设前面$i$列处理完后,已知第$i$列的最小值$=(10101101)_{2}$

    而第$i+1$列允许为$1$的位(从左到右,从$1$开始)有第$1,2,3,4,5,6$位

    加入没有限制,那么第$i+1$列的最优解$=(10101110)_{2}$

    但是允许为$1$的位不包括第$7$位鸭

    于是我们就只能再向左找,找到第$4$位

    把第$4$位改为$1$,并将右边所有位改为$0$

    最后第$i+1$列的最优解$=(10110000)_{2}$

    即为:

    $a[i]=(10101101)_{2}$

    $a[i+1]=(10110000)_{2}$

    然后顺便维护下答案就ok了

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<set>
    
    namespace IO {
        const int lim = (1 << 20) + 500;
    
        char buf[lim + 5], *S, *T;
    
        inline char gc() {
            if (S == T) {
                T = (S = buf) + fread(buf, 1, lim, stdin);
                if (S == T) return EOF;
            }
            return *S++;
        }
    
        inline int read() {
            int x; char c; bool f;
            for (f = 0; (c = gc()) < '0' || c > '9'; f = c == '-');
            for (x = c ^ '0'; (c = gc()) >= '0' && c <= '9'; x = (x << 1) + (x << 3) + (c ^ '0'));
            return f ? -x : x;
        }
    }
    using namespace IO;//快读是题目给的(逃
    
    using namespace std;
    const int mod=1e9+7;
    int n,m,q,stk[500005],v[500005],tp;
    set <int> s[1005];
    set <int>::iterator it;
    int Pow(int x,int y){
        int re=1;
        for(;y;y>>=1,x=1ll*x*x%mod)
            if(y&1) re=1ll*re*x%mod;
        return re;
    }
    int solve(){
        int re=0; tp=0;
        for(int i=1,j;i<=n;++i){
            stk[tp+1]=m+1;
            for(j=1;j<=tp&&s[i].count(stk[j]);++j);//这一位填不了的话就从这位开始找
            tp=j-1;
            for(;;){
                it=s[i].upper_bound(stk[tp+1]-1);
                if(it==s[i].begin()) return -1;
                --it;
                if(*it>stk[tp]){stk[++tp]=*it; break;}
                if(!tp) return -1;
                --tp;
            }
            v[tp]=v[tp-1]+Pow(2,m-stk[tp]);//上个的答案(用数组维护)加上这一位
            if(v[tp]>=mod) v[tp]-=mod;
            re+=v[tp];
            if(re>=mod) re-=mod;
        }return re;
    }
    int main(){
        freopen("price.in","r",stdin);
        freopen("price.out","w",stdout);
        n=read(); m=read(); q=read();
        int q1,q2;
        while(q--){
            if(read()==1){
                q1=read(); q2=read();
                if(s[q1].count(q2)) s[q1].erase(q2);
                else s[q1].insert(q2);
            }else printf("%d
    ",solve());
        }return 0;
    }
  • 相关阅读:
    sqlplus时报Linux-x86_64 Error: 13: Permission denied
    thrift之TTransport层的缓存传输类TBufferedTransport和缓冲基类TBufferBase
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 新建Microsoft world文档
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 快乐司机
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 队列操作
    Java实现 蓝桥杯 算法提高 文本加密
    Java实现 蓝桥杯 算法提高 合并石子
  • 原文地址:https://www.cnblogs.com/kafuuchino/p/10440953.html
Copyright © 2011-2022 走看看