2018年7月16日暑假训练日记

  怎么说呢,刚开始做的缘故吧,感觉阻力挺大的。但是尽力都搞懂吧。

  昨天刚来的时候做了一道题,当时看了不少题也想了不少,但是发现真正能实施的不多,第一个出来的也是我认为比较没有阻力的题目是:

1001 Assignment,这道题听世冬说是个数据结构的贪心解法,但是我以前见过类似的尺取法的题目,所以思路直接就跑向了尺取法,本来信心慢慢,可是发现维护最大最小值并不是简单的区间移动怎么简单,于是加入了线段树优化,最简单的题目过的也不是很顺当。但是思路完全是自己的,并不知道题解怎么写的。

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define maxn 100010
using namespace std;
long long a[maxn];
struct xtree{
 long long l,r,maxx,minn;
}tree[4*maxn];
void build(long long id,long long l,long long r){
    tree[id].l=l,tree[id].r=r;
    if(l==r){
        tree[id].maxx=a[l],tree[id].minn=a[l];
    }
    else{
        long long mid=(l+r)>>1;
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
        tree[id].maxx=max(tree[id*2].maxx,tree[id*2+1].maxx);
        tree[id].minn=min(tree[id*2].minn,tree[id*2+1].minn);
    }
}
long long maxquery(long long id,long long l,long long r){
    if(tree[id].l==l&&tree[id].r==r) return tree[id].maxx;
    else{
        long long mid=(tree[id].l+tree[id].r)>>1;
        if(r<=mid) return maxquery(id*2,l,r);
        else if (l>mid)return maxquery(id*2+1,l,r);
        else{
            return max(maxquery(id*2,l,mid),maxquery(id*2+1,mid+1,r));
        }
    }
}
long long minquery(long long id,long long l,long long r){
    if(tree[id].l==l&&tree[id].r==r) return tree[id].minn;
    else{
        long long mid=(tree[id].l+tree[id].r)>>1;
        if(r<=mid) return minquery(id*2,l,r);
        else if (l>mid)return minquery(id*2+1,l,r);
        else{
            return min(minquery(id*2,l,mid),minquery(id*2+1,mid+1,r));
        }
    }
}
int main(){
    long long t;
    long long i,j,k,l,n,r;
    long long maxx,minn,tot,ans,temp;
    scanf("%lld",&t);
    while (t--){
        scanf("%lld%lld",&n,&k);
        for (i=1;i<=n;i++)scanf("%lld",&a[i]);
        build(1,1,n);
        maxx=minn=a[1];
        tot=1,ans=0;
        if (n==1){
            puts("1");
            continue;
        }
        l=1;
        for (i=2;i<=n;i++){
            if (a[i]>maxx)maxx=a[i];
            if (a[i]<minn)minn=a[i];
            if (maxx-minn>=k){
                ans+=tot*(tot+1)/2;
                for (j=l;j<=i;j++){
                    if (a[j]<maxx&&a[j]>minn){
                        tot--;
                        l++;
                        continue;
                    }
                    else {
                        l++;
                        tot--;
                        maxx=maxquery(1,l,i);
                        minn=minquery(1,l,i);
                        if (maxx-minn<k){
                            break;
                        }
                    }
                }
                ans-=tot*(tot+1)/2;
            }
            tot++;
            if (i==n){
                ans+=tot*(tot+1)/2;
            }
        }
        printf("%lld\n",ans);
    }
}
然后是一个线段树的题目1018 Gorgeous Sequence(中间看了一道疑似二分法+瞎搞的题目一直tle,是1009Y sequence,我认为的复杂度<64*64*30000,自认为不会超时,看了一眼题解的题头是个容斥定理,但感觉并非, 不知道容斥什么)这道题比较麻烦,是对lazy标记的理解,队友给我说的他看的大致的题解思路,和我的相似于是试了一下,最后还是借助了题解,处理不好总tle。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define maxn 4000010
const long long inf=1000000000;
using namespace std;
long long maxx,sum;
struct xtree{
    long long l,r;
    long long mid(){
        return (l+r)/2;
    }
    long long lazy;
    long long flag;
    long long sum,maxx;
}tree[maxn];
long long a[1000010];
void pushup(long long id){
    tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
    tree[id].maxx=max(tree[id*2].maxx,tree[id*2+1].maxx);
    tree[id].flag=tree[id*2].flag+tree[id*2+1].flag;
}
void build(long long id,long long l,long long r){
    tree[id].l=l;
    tree[id].r=r;
    tree[id].lazy=0;
    if (l==r){
        tree[id].flag=1;
        tree[id].lazy=tree[id].sum=tree[id].maxx=a[l];
        return ;
    }
    long long mid=tree[id].mid();
    build(id*2,l,mid);
    build(id*2+1,mid+1,r);
    pushup(id);
}
void renew(long long id,long long num){
    if (tree[id].lazy<=num&&tree[id].lazy)return ;
    tree[id].lazy=num;
    tree[id].sum=tree[id].sum+(tree[id].r-tree[id].l+1-tree[id].flag)*num;
    if (tree[id].flag<tree[id].r-tree[id].l+1){
        tree[id].maxx=num;
        tree[id].flag=tree[id].r-tree[id].l+1;
    }
}
void pushdown(long long id){
    if (!tree[id].lazy)return ;
    long long mid=tree[id].mid();
    renew(id*2,tree[id].lazy);
    renew(id*2+1,tree[id].lazy);
    tree[id].lazy=0;
}
void find(long long id,long long num){
    if (tree[id].maxx<=num)return;
    if (tree[id].lazy>num)tree[id].lazy=0;
    if (tree[id].l==tree[id].r){
        tree[id].maxx=tree[id].lazy;
        tree[id].sum=tree[id].lazy;
        tree[id].flag=tree[id].lazy?1:0;
        return;
    }
    pushdown(id);
    long long mid=tree[id].mid();
    find(id*2,num);
    find(id*2+1,num);
    pushup(id);
}
void update(long long id,long long l,long long r,long long num){
    if (tree[id].maxx<=num)return ;
    if (tree[id].l>=l&&r>=tree[id].r){
        find(id,num);
        renew(id,num);
        return;
    }
    pushdown(id);
    long long mid=tree[id].mid();
    if(l<=mid) update(id*2,l,r,num);
    if(r>mid) update(id*2+1,l,r,num);
    pushup(id);
}
void query(long long id,long long l,long long r){
    if (l<=tree[id].l&&r>=tree[id].r){
        sum+=tree[id].sum;
        maxx=max(maxx,tree[id].maxx);
        return;
    }
    pushdown(id);
    long long mid=tree[id].mid();
    if(l<=mid) query(id*2,l,r);
    if(r>mid) query(id*2+1,l,r);
}
int main(){
    long long t,n,q,i,j,c,x,y,z;
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&q);
        for (i=1;i<=n;i++)scanf("%lld",&a[i]);
        build(1,1,n);
        while(q--){
            scanf("%lld",&c);
            if (!c){
                scanf("%lld%lld%lld",&x,&y,&z);
                update(1,x,y,z);
            }
            else if(c==1){
                sum=0;
                maxx=-inf;
                scanf("%lld%lld",&x,&y);
                query(1,x,y);
                printf("%d\n",maxx);
            }
            else{
                sum=0;
                maxx=-inf;
                scanf("%lld%lld",&x,&y);
                query(1,x,y);
                printf("%lld\n",sum);
            }
        }
    }
}

然后一个小的暴力题目:1017 Friends,题意求分组方法,但是人数很少,明显暴力,因为有个大的剪枝方案,一开始图省事少用一个数组wr了一发,后来加上秒过。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
long long vis1[9];
long long vis2[9];
long long d[9];
long long n,m,ans;
struct edge{
    long long x;
    long long y;
}p[29];
void dfs(long long id){
    if (id==m+1){
        long long i;
        bool flag=1;
        for (i=1;i<=n;i++){
            if (vis1[i]!=vis2[i]){
                flag=0;
                break;
            }
        }
        if (flag)ans++;
        return;
    }
    if (vis1[p[id].x]<d[p[id].x]/2&&vis1[p[id].y]<d[p[id].y]/2){
        vis1[p[id].x]++;
        vis1[p[id].y]++;
        dfs(id+1);
        vis1[p[id].x]--;
        vis1[p[id].y]--;
    }
    if (vis2[p[id].x]<d[p[id].x]/2&&vis2[p[id].y]<d[p[id].y]/2){
        vis2[p[id].x]++;
        vis2[p[id].y]++;
        dfs(id+1);
        vis2[p[id].x]--;
        vis2[p[id].y]--;
    }
}

int main(){
    long long t;
    long long i,j;
    scanf("%lld",&t);
    while (t--){
        scanf("%lld%lld",&n,&m);
        memset (d,0,sizeof(d));
        for (i=1;i<=m;i++){
            scanf("%lld%lld",&p[i].x,&p[i].y);
            d[p[i].x]++;
            d[p[i].y]++;
        }
        ans=0;
        bool flag=1;
        for (i=1;i<=n;i++){
            if (d[i]%2!=0){
                flag=0;
                break;
            }
        }
        if (flag){
            dfs(1);
            printf("%lld\n",ans);
        }
        else {
            puts("0");
        }
    }
}
之后是都过了的谜之第一题,据说都参考了题解,于是我问队友是不是前面扫一遍后边扫一遍(我一开始的想法)这逗逼说不是,下午又给我说是,还赖帐不认了,但是知道是对的就很自信的写过了。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#define maxn 100010
using namespace std;
vector<long long>p[10010];
void getp(){
    long long i,j;
    for (i=1;i<=10000;i++){
        for (j=1;j<=sqrt(i);j++){
            if (i%j==0){
                p[i].push_back(j);
                if (i/j!=j){
                    p[i].push_back(i/j);
                }
            }
        }
    }
}
long long a[maxn];
long long vis[maxn];
long long pre[maxn];
long long to[maxn];
int main(){
    getp();
    long long n,i,j,k,l;
    while (scanf("%lld",&n)!=EOF){
        for (i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            pre[i]=0;
            to[i]=n+1;
        }
        memset (vis,-1,sizeof(vis));
        vis[a[1]]=1;
        for (i=2;i<=n;i++){
            for (j=0;j<p[a[i]].size();j++){
                if (vis[p[a[i]][j]]!=-1&&vis[p[a[i]][j]]>pre[i]){
                    pre[i]=vis[p[a[i]][j]];
                }
            }
            vis[a[i]]=i;
        }
        memset (vis,-1,sizeof(vis));
        vis[a[n]]=n;
        for (i=n-1;i>=1;i--){
            for (j=0;j<p[a[i]].size();j++){
                if (vis[p[a[i]][j]]!=-1&&vis[p[a[i]][j]]<to[i]){
                    to[i]=vis[p[a[i]][j]];
                }
            }
            vis[a[i]]=i;
        }
        long long ans=0;
        for (i=1;i<=n;i++){
            //cout<<i<<' '<<pre[i]<<' '<<to[i]<<endl;
            ans=(ans+(to[i]-i)*(i-pre[i]))%1000000007;
        }
        printf("%lld\n",ans);
    }
}
 

猜你喜欢

转载自blog.csdn.net/m0_37772713/article/details/81070473