其他分享
首页 > 其他分享> > 【2018.11.7】【luoguNOIp 热身赛】解题报告及总结

【2018.11.7】【luoguNOIp 热身赛】解题报告及总结

作者:互联网

reference:

暂告一段落,做的很爽!!
还剩5题,预计等国庆集训完再回来做

NOIp热身赛 比赛列表

P5142 区间方差

这题挺模板的,暴力单点修改,推一推方差的公式,发现只需要sum和ssum(区间平方和),然后逆元啥的……自己搞(为了练手,用了扩欧,当然ksm也是过得了的)

#include<bits/stdc++.h>
using namespace std;
#define int long long
template <typename T>inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;} 
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)

#define lson o<<1
#define rson o<<1|1
const int N=100010,mod=1e9+7;

struct tree{
    int l,r;
    int sum,ssum;
}t[N<<2];

int val[N];
int n,m;

inline void exgcd(int a,int b,int &x,int &y){
    if(!b)x=1,y=0;
    else exgcd(b,a%b,y,x),y-=a/b*x;
}

int inv(int a){
    int x,y;
    exgcd(a,mod,x,y);
    return (x+mod)%mod;
}

inline void pushup(int o){
    t[o].sum=(t[lson].sum+t[rson].sum)%mod;
    t[o].ssum=(t[lson].ssum+t[rson].ssum)%mod;
}

inline void build(int o,int l,int r){
    t[o].l=l,t[o].r=r;
    if(l==r){
        t[o].sum=val[l]%mod;
        t[o].ssum=1LL*val[l]*val[l]%mod;
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(o);
}

inline void change(int o,int pos,int k){
    int l=t[o].l,r=t[o].r;
    if(pos==l && pos==r){
        t[o].ssum=1LL*k*k%mod;
        t[o].sum=k%mod;
        return ;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)change(lson,pos,k);
    else change(rson,pos,k);
    pushup(o);
}

inline int query_sum(int o,int x,int y){
    int l=t[o].l,r=t[o].r;
    if(x<=l && r<=y){
        return t[o].sum;
    }
    int res=0;
    int mid=(l+r)>>1;
    if(x<=mid)res=(res+query_sum(lson,x,y))%mod;
    if(mid<y)res=(res+query_sum(rson,x,y))%mod;
    return res;
}

inline int query_ssum(int o,int x,int y){
    int l=t[o].l,r=t[o].r;
    if(x<=l && r<=y){
        return t[o].ssum;
    }
    int res=0;
    int mid=(l+r)>>1;
    if(x<=mid)res=(res+query_ssum(lson,x,y))%mod;
    if(mid<y)res=(res+query_ssum(rson,x,y))%mod;
    return res;
}

#undef int
int main(){
#define int long long
    #ifdef WIN32
    freopen("fangcha.txt","r",stdin);
    #endif 
    rd(n),rd(m);
    rep(i,1,n)rd(val[i]);
    build(1,1,n);
    while(m--){
        int op,x,k,y;
        rd(op);
        if(op==1){
            rd(x),rd(k);
            change(1,x,k);
        }
        else if(op==2){
            rd(x),rd(y);
            /*
            方差=(a1^2+a2^2+...+an^2)/n  -  a_ba^2; 
            */
            int len=inv(y-x+1);
            int sum=query_sum(1,x,y)%mod;
            int qsum=query_ssum(1,x,y)%mod;
            qsum=qsum*len%mod;
            int ba=sum*len%mod;
            int ave=ba*ba%mod;
            int ans=qsum-ave;
            while(ans<0)ans+=mod;//如果不加这句只能得10 pts!!! 
            printf("%lld\n",ans);
        }
    }
    return 0;
}

P1471 方差(上道题的哥哥)

还要维护一个区间加操作(自己再推一遍如何更新的)

然鹅最坑的点是加的这个数k是一个实数阿伟调了好久好久!!!!

主要是update(int o,int x,int y,int k)
的int k要写成 double k啊我真是个智娃。

以后看到题上写了实数俩字儿的时候请千万小心!

#include<bits/stdc++.h>
using namespace std;
template <typename T>inline void rd(T &x){x=0;char c=getchar();int f=0;while(!isdigit(c)){f|=c=='-';c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}x=f?-x:x;} 
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define dwn(i,a,b) for(int i=a;i>=b;--i)
#define mem(a,b) memset(a,b,sizeof(a))
#define ee(i,u) for(int i=head[u];i;i=e[i].next)

#define lson o<<1
#define rson o<<1|1
const int N=100010;

struct tree{
    int l,r;
    double sum,ssum,tag_add;
}t[N<<2];

double val[N];
int n,m;

inline void pushup(int o){
    t[o].sum=(t[lson].sum+t[rson].sum);
    t[o].ssum=(t[lson].ssum+t[rson].ssum);
}

inline void f(double delta,int o){
    int l=t[o].l,r=t[o].r;
    t[o].tag_add+=delta;
    t[o].ssum=t[o].ssum+2*delta*t[o].sum+delta*delta*(r-l+1);
    t[o].sum+=delta*(r-l+1);
} 

inline void pushdown(int o){
    if(t[o].tag_add){
        f(t[o].tag_add,lson);
        f(t[o].tag_add,rson);
        t[o].tag_add=0;
    }
}

inline void build(int o,int l,int r){
    t[o].tag_add=0;
    t[o].l=l,t[o].r=r;
    if(l==r){
        t[o].sum=val[l];
        t[o].ssum=val[l]*val[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(o);
}

inline void update(int o,int x,int y,double k){
    int l=t[o].l,r=t[o].r;
    if(x<=l && r<=y){
        f(k,o);
        return ;
    }
    pushdown(o);
    int mid=(l+r)>>1;
    if(x<=mid)update(lson,x,y,k);
    if(mid<y)update(rson,x,y,k);
    pushup(o);
} 

inline double query_sum(int o,int x,int y){
    int l=t[o].l,r=t[o].r;
    if(x<=l && r<=y){
        return t[o].sum;
    }
    pushdown(o);
    double res=0;
    int mid=(l+r)>>1;
    if(x<=mid)res=(res+query_sum(lson,x,y));
    if(mid<y)res=(res+query_sum(rson,x,y));
    return res;
}

inline double query_ssum(int o,int x,int y){
    int l=t[o].l,r=t[o].r;
    if(x<=l && r<=y){
        return t[o].ssum;
    }
    pushdown(o);
    double res=0;
    int mid=(l+r)>>1;
    if(x<=mid)res=(res+query_ssum(lson,x,y));
    if(mid<y)res=(res+query_ssum(rson,x,y));
    return res;
}

int main(){
    #ifdef WIN32
    freopen("fangcha.txt","r",stdin);
    #endif
    rd(n),rd(m);
    rep(i,1,n)scanf("%lf",&val[i]);
    build(1,1,n);
    while(m--){
        int op,x,y;
        double k;
        rd(op);
        if(op==1){
            rd(x),rd(y);scanf("%lf",&k);
            update(1,x,y,k);
        }
        else if(op==2){
            rd(x),rd(y);
            double ans=query_sum(1,x,y)/(y-x+1);
            printf("%.4lf\n",ans); 
        }
        else if(op==3){
            rd(x),rd(y);
            double sum1=query_ssum(1,x,y)/(y-x+1);
            double sum2=query_sum(1,x,y)/(y-x+1);
            printf("%.4lf\n",sum1-sum2*sum2);
        }
    }
    return 0;
}

P5146 最大差值[胸中的日月]

智娃水题,由于j>i,所以对于每一个j前的数,最小值是一定的!那么我们存一下minn,不断更新ans=max(ans,x-minn)就可以O(n)啦

P1890 gcd区间 ST表

当你,有上线段树的冲动时,不妨看看ST表能不能搞。
显然,gcd是满足区间可“加”性的。而有没有什么修改操作……ST表无疑是一个酷酷的选择。(而且又好写又好调)

P2434 [SDOI2005]区间(合并区间模型)

P2082 区间覆盖(加强版)上一题的弟弟

在找到一个符合条件的区间的时候更新一下长度就好啦,没什么难的

P5077 Tweetuzki 爱等差数列 推公式

不开long long见祖宗

手推一下柿子,倒序枚举,找到直接退出(这样可以保证找到的a1是最小的)。

    rd(s); 
    int tot=sqrt(2*s)+1;
    dwn(i,tot,1){
        if((s*2+i-i*i)%(2*i)==0 && (s*2+i-i*i)/*分母>0,如果不写这句会WA两个点*/){
            printf("%lld %lld\n",(s*2+i-i*i)/(2*i),(s*2+i-i*i)/(2*i)+i-1);
            break;
        }
    }

P5144 蜈蚣 前缀异或和+dp

前缀异或和+dp

f[i][j]表示前i个位置放了j个^符号(分成了j+1段)

初值:f[i][0]=sum[i]

状态转移:
由区间[1,j-1][j,i]来更新f[i][k]

rep(i,1,n)
    rep(k,1,min(m,i-1))
        rep(j,k,i)
            f[i][k]=max(f[i][k],f[j-1][k-1]+(sum[i]^sum[j-1]));

P5149 会议座位 归并排序+map

很明显,在n<=1e5的情况下,逆序对最坏情况下是会达到100000*(100000-1)/2 == 4,999,950,000‬的!!这超出了int 的范围,要开long long.

不要每次等WA了再重新分析数据范围,要一遍就想明白。考场上不会有提交的feedback!

P5150 生日礼物 唯一分解定理

一看见lcm(a,b)==n这么巧!!!
对于n分解素数,n=p1^c1+p2^c2+p3^c3+...+pn^cn那么对于每一个质数pi,都有max(ci_a,ci_b)=ci;

开始讨论:当ci_a==ci,那么b有ci+1种选法(0也要算上),同理,当ci_b==ci,那么a有ci+1种选法

加起来是2ci+2种,而当ci_a==ci_b==ci的这种情况被算了两边,再-1,得对于每一个素数是2*c[i]+1种,用乘法原理乘起来即可

不要忘了n本身是一个大质数的情况

标签:ci,2018.11,int,sum,long,luoguNOIp,区间,热身赛,define
来源: https://www.cnblogs.com/sjsjsj-minus-Si/p/11634657.html