zoukankan      html  css  js  c++  java
  • QZS8.18

    咳咳。。。这场考试摸了

    T1蓝蓝的棋盘

    我菜炸了。。。

    这竟然是个dp。。。长得真像博弈论

    80分做法:设dp[x]表示棋子目前在位置x的答案(先手减去后手的分数).

    状态转移方程dp[xl=max(a[y]-dp[y])(x<y<=min(n,x+m)),且dp[n]=0

    直接枚举y转移即可,复杂度O(nm)

    100分做法: 单调队列优化 复杂度O(n)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    inline long long read(){
    	long long x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    int n;
    long long l,r;
    long long f[500005],m,a[500005],s[500005],q[500005];
    int main() {
        n=read();m=read();
        for(int i=1;i<=n;i++)
            a[i]=read();
        l=1,r=1;
        f[n]=0;q[1]=n;
        for(int i=n-1;i>=0;i--) {
            while(l<=r&&q[l]>i+m) l++;
            f[i]=a[q[l]]-f[q[l]];
            while(l<=r&&(a[q[r]]-f[q[r]])<=(a[i]-f[i])) r--;
            q[++r]=i;
        }
        printf("%lld
    ",f[0]);
        return 0;
    }
    

    T2淘淘的集合

    操作1:启发式合并,就把小的集合(vector维护)暴力拆开,合并到大集合上

    操作2:每个集合维护个tag标记,然后直接在标记上加O(1)

    以上两个操作不是直接做的,要记录下来等询问的时候再做

    操作3:清空,我们记录一个清空时间,这里可以用分块开个数组,然后某区间赋值为时间

    操作4:查询,把区间查询化为单点查询

    我们现在就是要用个数据结构,支持区间赋值,单点查询——线段树

    查询这段清空时间pretime,用前缀和相减的方法a[nowtime]-a[pretime]

    复杂度迷人。。。

    ​ 具体的代码+注释见下

    #include <iostream>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define ll long long
    #define ls (p<<1)
    #define rs (p<<1|1)
    #define mid ((l+r)>>1)
    inline ll read(){
    	ll x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
    	return f*x;
    }
    const ll N=4e6+5;
    ll n,m,tot,a[N];
    ll ans[N];
    ll fa[N],set_tag[N];//每个集合的tag
    inline ll find(ll x) {
        return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    struct question {
        bool add;
        ll id,pos;
        question () {}
        question (bool add_,ll id_,ll pos_):add(add_),id(id_),pos(pos_){}
    };
    vector<ll>v[N];//集合
    vector<question>ask[N];//询问4
    struct option{
        ll id,x,y;
        option() {}
        option(ll id_,ll x_,ll y_):id(id_),x(x_),y(y_){}
    }op[N];
    
    ll tag[N],tim[N];
    void build(ll l,ll r,ll p){
        tag[p]=-1;//tag必须赋值-1,因为要和时间为0的区别开
        if(l==r) return;
        build(l,mid,ls);
        build(mid+1,r,rs);
    }
    inline void pushdown(ll p) {
        if(tag[p]==-1) return;
        tag[ls]=tag[rs]=tag[p];
        tag[p]=-1;
    }
    void change(ll l,ll r,ll L,ll R,ll v,ll p) {
        if(l>R||r<L) return;
        if(L<=l&&r<=R) {tag[p]=v;return;}
        pushdown(p);
        change(l,mid,L,R,v,ls);
        change(mid+1,r,L,R,v,rs);
    }
    void query(ll l,ll r,ll L,ll R,ll p) {
        if(l>R||r<L) return;
        if(L<=l&&r<=R&&tag[p]!=-1) {//注意!!!tag为-1说明这个区间的点没改过,time为0就不用赋成tag了
            for(ll i=l;i<=r;i++)
                tim[i]=tag[p];
            return;
        }
        pushdown(p);
        query(l,mid,L,R,ls);
        query(mid+1,r,L,R,rs);   
    }
    void merge(ll x,ll y) {
        if(x==y) return;
        if(v[x].size()<v[y].size()) swap(x,y);
        for(ll i=0;i<v[y].size();i++) {
            ll now=v[y][i];
            a[now]+=set_tag[y]-set_tag[x];//把y合并到x上后,y的标记会变成x的标记,为使其值不变,所以要进行这步
            v[x].push_back(now);
        }
        fa[find(y)]=find(x);
    }
    inline ll get(ll x){
        return a[x]+set_tag[find(x)];
    }
    int main() {
        n=read();m=read();
        for(ll i=1;i<=n;i++) 
            fa[i]=i,v[i].push_back(i);
    
        build(1,n,1);
        for(ll i=1,c,l,r;i<=m;i++) {
            c=read();l=read();r=read();
            if(c==1||c==2) {
                op[i]=option(c,l,r);//操作1,2先离线下来,等有4的时候再用
            } else if(c==3) {
                change(1,n,l,r,i,1);//区间赋值,线段树就是维护 time
            } else {
                ++tot;//询问编号
                query(1,n,l,r,1);//这里复杂度迷人。。。O(n)?
                for(ll j=l;j<=r;j++) {//把区间查询改成单点查询
                    ask[tim[j]].push_back(question(0,tot,j));
                    ask[i].push_back(question(1,tot,j));
                }
            }
        }
        //注意没修改的时间为0,所以从0开始
        for(ll i=0;i<=m;i++) {
            ll fx=find(op[i].x);
            if(op[i].id==1) merge(fx,find(op[i].y));
            if(op[i].id==2) set_tag[fx]+=op[i].y;
            for(ll j=0;j<ask[i].size();j++) 
                if(ask[i][j].add) ans[ask[i][j].id]+=get(ask[i][j].pos);
                else ans[ask[i][j].id]-=get(ask[i][j].pos);
        }
        for(ll i=1;i<=tot;i++)
            printf("%lld
    ",ans[i]);
        return 0;
    }
    

    T3

    数学公式

    O(1)时间内算出1−n四次方和的公式

    https://www.cnblogs.com/BlogOfchc1234567890/p/9863162.html

    9,10好像是单调栈

    具体转化就是把一段为1的数搞成个矩形。。。然后啥最大矩形面积...gugugu

  • 相关阅读:
    [LeetCode] Meeting Rooms I & II
    [LeetCode] Graph Valid Tree
    [LeetCode] Palindrome Permutation I & II
    [LeetCode] Encode and Decode Strings
    [LeetCode] Paint Fence
    android 发送短信功能
    andrioid 分享到其它(短信,qq,微信等功能)
    android Dialog实例
    android开发之onCreate( )方法详解
    android edittext属性说明
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13543002.html
Copyright © 2011-2022 走看看