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\n",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\n",ans[i]);
    return 0;
}

T3

数学公式

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

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

9,10好像是单调栈

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

posted @ 2020-08-21 19:44  ke_xin  阅读(38)  评论(0编辑  收藏  举报