2018年9月9日开学训练日记

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m0_37772713/article/details/82560860

  周六的比赛情况:

  前两个小时做自己的c题,后来发现推不动,容斥复杂度过高,然后就转移阵地了。

  之后:

  助攻了k题,发现了题意读错了,然后修改之后过了。

  助攻+完成了g题,一并推出容斥,并完成代码提交,代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define maxn 100010
using namespace std;
const long long mo=1000000007;
long long fun;
bool vis[maxn];
long long prime[maxn];
long long inv2,inv3,inv6;
long long fac[32];
long long box[32];
long long tot;
long long total;
long long n,m;
long long qpow(long long x,long long y){
    if (x==0)return 0;
    long long ans=1;
    long long k=x;
    while(y){
        if(y&1)ans=ans*k%mo;
        k=k*k%mo;
        y>>=1;
    }
    return (ans+mo)%mo;
}
void getprime(){
    long long i,j;
    tot=0;
    memset (vis,0,sizeof(vis));
    for (i=2;i<maxn;i++){
        if (!vis[i]){
            prime[++tot]=i;
            for (j=i+i;j<maxn;j+=i){
                vis[j]=1;
            }
        }
    }
}
long long getfac(long long x){
    long long cnt=0;
    long long i;
    for (i=1;i<=tot&&prime[i]*prime[i]<=x;i++){
        if(x%prime[i]==0){
            fac[++cnt]=prime[i];
            while(x%prime[i]==0){
                x=x/prime[i];
            }
        }
    }
    if(x>1) fac[++cnt]=x;
    return cnt;
}
long long cal(long long x,long long temp){
    return (temp*x%mo*(x+1)%mo*inv2%mo+temp*temp%mo*x%mo*(x+1)%mo*(2*x+1)%mo*inv6%mo+mo)%mo;
}
void sfind(long long x,long long y,long long z,long long val){
    long long i,j;
    for (i=x;i<=total;i++){
        if (total-i<z-y)return ;
        box[y]=fac[i];
        if (y==z){
            long long temp=1;
            for (j=1;j<=z;j++){
                temp=temp*box[j];
            }
            fun=(fun+cal(n/temp,temp))%mo;
        }
        else sfind(i+1,y+1,z,val);
    }
}
long long solve(long long x){
    long long i,j;
    long long temp=-1;
    long long ans=(x*(x+1)%mo*(x+2)%mo)*inv3%mo;
    for (i=1;i<=total;i++){
        fun=0;
        sfind(1,1,i,x);
        ans=(ans+fun*temp%mo)%mo;
        temp=-temp;
    }
    return ans;
}
int main(){
    long long i,j;
    getprime();
    inv2=qpow(2,mo-2);
    inv3=qpow(3,mo-2);
    inv6=qpow(6,mo-2);
    while (scanf("%lld%lld",&n,&m)!=EOF){
        total=getfac(m);
        long long ans=solve(n);
        cout<<(ans+mo)%mo<<endl;
    }
}

  助攻了i题,发现代码中复杂度过高的部分。

  赛后发现c题可以用莫比乌斯函数优化,但是理解深度不够。

  周天徐州站的比赛情况:

  前一个半小时做自己的c题,后来发现时间复杂度不对(后群里说样例也水),然后转移阵地。

  之后:

  做出了h题,看到题意之后,想出来了完整的思路,并很快ac,总体是个双线段树+思维,代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define maxn 1000010
using namespace std;
long long a[maxn];
long long n;
struct xtree{
    long long l,r;
    long long sum;
    long long mid(){
        return (l+r)/2;
    }
}tree[maxn];
void pushup(long long id){
    tree[id].sum=tree[id*2].sum+tree[id*2+1].sum;
}
void build(long long id,long long l,long long r){
    tree[id].l=l;
    tree[id].r=r;
    if (l==r){
        tree[id].sum=a[l];
        return ;
    }
    long long mid=tree[id].mid();
    build(id*2,l,mid);
    build(id*2+1,mid+1,r);
    pushup(id);
}
void update(long long id,long long pos,long long val){
    if (tree[id].l==tree[id].r){
        tree[id].sum=val;
        return ;
    }
    long long mid=tree[id].mid();
    if (pos<=mid){
        update(id*2,pos,val);
    }
    else {
        update(id*2+1,pos,val);
    }
    pushup(id);
}
long long query(long long id,long long l,long long r){
    if (tree[id].l>=l&&tree[id].r<=r){
        return tree[id].sum;
    }
    long long mid=tree[id].mid();
    if (r<=mid){
        return query(id*2,l,r);
    }
    else if (l>mid){
        return query(id*2+1,l,r);
    }
    else {
        return query(id*2,l,mid)+query(id*2+1,mid+1,r);
    }
}
struct xtree1{
    long long l,r;
    long long sum;
    long long mid(){
        return (l+r)/2;
    }
}tree1[maxn];
void pushup1(long long id){
    tree1[id].sum=tree1[id*2].sum+tree1[id*2+1].sum;
}
void build1(long long id,long long l,long long r){
    tree1[id].l=l;
    tree1[id].r=r;
    if (l==r){
        tree1[id].sum=(n-l+1)*a[l];
        return ;
    }
    long long mid=tree1[id].mid();
    build1(id*2,l,mid);
    build1(id*2+1,mid+1,r);
    pushup1(id);
}
void update1(long long id,long long pos,long long val){
    if (tree1[id].l==tree1[id].r){
        tree1[id].sum=(n-tree1[id].l+1)*val;
        return ;
    }
    long long mid=tree1[id].mid();
    if (pos<=mid){
        update1(id*2,pos,val);
    }
    else {
        update1(id*2+1,pos,val);
    }
    pushup1(id);
}
long long query1(long long id,long long l,long long r){
    if (tree1[id].l>=l&&tree1[id].r<=r){
        return tree1[id].sum;
    }
    long long mid=tree1[id].mid();
    if (r<=mid){
        return query1(id*2,l,r);
    }
    else if (l>mid){
        return query1(id*2+1,l,r);
    }
    else {
        return query1(id*2,l,mid)+query1(id*2+1,mid+1,r);
    }
}
int main(){
    long long i,j;
    long long m,x,y,z;
    while (scanf("%lld%lld",&n,&m)!=EOF){
        for (i=1;i<=n;i++)scanf("%lld",&a[i]);
        build(1,1,n);
        build1(1,1,n);
        while (m--){
            long long flag;
            scanf("%lld",&flag);
            if (flag==1){
                scanf("%lld%lld",&x,&y);
                printf("%lld\n",query1(1,x,y)-(n-x+1-(y-x+1))*query(1,x,y));
            }
            else {
                scanf("%lld%lld",&x,&y);
                update(1,x,y);
                update1(1,x,y);
            }
        }
    }
}
 

  做出了g题,被纪翔文告知了思路,后用双线段树+离散处理,因为我处理时间过长,纪翔文同时开了树状数组的写法,最后同时ac,代码:

#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#define maxn 200010
#define maxx 10000010
using namespace std;
long long cntx[maxx];
long long cnty[maxx];
struct point{
    long long x;
    long long y;
    long long id;
}p[maxn];
bool cmpx(point a,point b){
    if(a.x<b.x)return 1;
    else if(a.x==b.x){
        if(a.y<b.y)return 1;
        else return 0;
    }
    return 0;
}
bool cmpy(point a,point b){
    if(a.y<b.y)return 1;
    else if(a.y==b.y){
        if(a.x<b.x)return 1;
        else return 0;
    }
    return 0;
}
bool cmpid(point a,point b){
    return a.id>b.id;
}
struct xtree{
    long long l,r;
    long long lazy;
    long long sum;
    long long mid(){
        return (l+r)/2;
    }
}treex[maxn];
void pushupx(long long id){
    treex[id].sum=treex[id*2].sum+treex[id*2+1].sum;
}
void pushdownx(long long id){
    if (treex[id].lazy){
        treex[id*2].lazy=treex[id].lazy;
        treex[id*2+1].lazy=treex[id].lazy;
        long long mid=treex[id].mid();
        treex[id*2].sum=treex[id].lazy*(mid-treex[id].l+1);
        treex[id*2+1].sum=treex[id].lazy*(treex[id].r-mid);
        treex[id].lazy=0;
    }
}
void buildx(long long id,long long l,long long r){
    treex[id].l=l;
    treex[id].r=r;
    treex[id].lazy=0;
    if (l==r){
        treex[id].sum=0;
        return ;
    }
    long long mid=treex[id].mid();
    buildx(id*2,l,mid);
    buildx(id*2+1,mid+1,r);
    pushupx(id);
}
void updatex(long long id,long long l,long long r,long long val){
    if (treex[id].l>=l&&treex[id].r<=r){
        treex[id].lazy=val;
        treex[id].sum=(treex[id].r-treex[id].l+1)*val;
        return ;
    }
    pushdownx(id);
    long long mid=treex[id].mid();
    if (r<=mid){
        updatex(id*2,l,r,val);
    }
    else if (l>mid){
        updatex(id*2+1,l,r,val);
    }
    else {
        updatex(id*2,l,mid,val);
        updatex(id*2+1,mid+1,r,val);
    }
    pushupx(id);
}
long long queryx(long long id,long long l,long long r){
    if (treex[id].l>=l&&treex[id].r<=r){
        return treex[id].sum;
    }
    pushdownx(id);
    long long mid=treex[id].mid();
    if (r<=mid){
        return queryx(id*2,l,r);
    }
    else if (l>mid){
        return queryx(id*2+1,l,r);
    }
    else {
        return queryx(id*2,l,r)+queryx(id*2+1,l,r);
    }
}

struct ytree{
    long long l,r;
    long long lazy;
    long long sum;
    long long mid(){
        return (l+r)/2;
    }
}treey[maxn];
void pushupy(long long id){
    treey[id].sum=treey[id*2].sum+treey[id*2+1].sum;
}
void pushdowny(long long id){
    if (treey[id].lazy){
        treey[id*2].lazy=treey[id].lazy;
        treey[id*2+1].lazy=treey[id].lazy;
        long long mid=treey[id].mid();
        treey[id*2].sum=treey[id].lazy*(mid-treey[id].l+1);
        treey[id*2+1].sum=treey[id].lazy*(treey[id].r-mid);
        treey[id].lazy=0;
    }
}
void buildy(long long id,long long l,long long r){
    treey[id].l=l;
    treey[id].r=r;
    treey[id].lazy=0;
    if (l==r){
        treey[id].sum=0;
        return ;
    }
    long long mid=treey[id].mid();
    buildy(id*2,l,mid);
    buildy(id*2+1,mid+1,r);
    pushupy(id);
}
void updatey(long long id,long long l,long long r,long long val){
    if (treey[id].l>=l&&treey[id].r<=r){
        treey[id].lazy=val;
        treey[id].sum=(treey[id].r-treey[id].l+1)*val;
        return ;
    }
    pushdowny(id);
    long long mid=treey[id].mid();
    if (r<=mid){
        updatey(id*2,l,r,val);
    }
    else if (l>mid){
        updatey(id*2+1,l,r,val);
    }
    else {
        updatey(id*2,l,mid,val);
        updatey(id*2+1,mid+1,r,val);
    }
    pushupy(id);
}
long long queryy(long long id,long long l,long long r){
    if (treey[id].l>=l&&treey[id].r<=r){
        return treey[id].sum;
    }
    pushdowny(id);
    long long mid=treey[id].mid();
    if (r<=mid){
        return queryy(id*2,l,r);
    }
    else if (l>mid){
        return queryy(id*2+1,l,r);
    }
    else {
        return queryy(id*2,l,r)+queryy(id*2+1,l,r);
    }
}

int main(){
    long long n,x,y;
    long long i;
    while (scanf("%lld",&n)!=EOF){
        for (i=1;i<=n;i++){
            scanf("%lld%lld",&p[i].x,&p[i].y);
            p[i].id=i;
        }
        sort (p+1,p+n+1,cmpx);
        long long totx=1;
        memset (cntx,0,sizeof(cntx));
        memset (cnty,0,sizeof(cnty));
        p[0].x=0;
        p[0].y=0;
        cntx[p[0].x]=1;
        for (i=1;i<=n;i++){
            if (p[i].x!=p[i-1].x){
                cntx[p[i].x]=++totx;
            }
        }
        buildx(1,1,totx);
        cnty[p[0].y]=1;
        long long toty=1;
        sort (p+1,p+n+1,cmpy);
        for (i=1;i<=n;i++){
            if (p[i].y!=p[i-1].y){
                cnty[p[i].y]=++toty;
            }
        }
        buildy(1,1,toty);
        sort (p+1,p+n+1,cmpid);
        long long ansx=0;
        long long ansy=0;
        for (i=1;i<=n;i++){
            long long tempx=queryx(1,cnty[p[i].y],cnty[p[i].y]);
            ansx=ansx+p[i].x-tempx;
            long long tempy=queryy(1,cntx[p[i].x],cntx[p[i].x]);
            ansy=ansy+p[i].y-tempy;
            updatex(1,cnty[tempy],cnty[p[i].y],p[i].x);
            updatey(1,cntx[tempx],cntx[p[i].x],p[i].y);
        }
        cout<<ansx+ansy<<endl;
    }
}
  然后就废了,调两个双线段树的代码确实很耗费精力,加上上午上完数学物理方程课过来的,就觉得头很疼。

猜你喜欢

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