zoukankan      html  css  js  c++  java
  • 20190808

    区间和2

    题意简述

    $T$ 组数据。

    每次给定长度为 $n$ 的序列,$q$ 组询问,每次询问 $l,r$ ,表示询问 $l-r$ 小的区间和。

    $Tleq 10,nleq 2 imes 10^5,qleq 20$。

    时间限制 $7s$

    $solution:$

    这种题一看就知道会是差分后二分答案吧,所以现在的问题变为求前 $k$ 小区间和。

    设 $S_k=sum_{i=1}^k a_i$ 。则现在要统计的是 $S_r-xleq S_{l-1}$ 的个数,和也这样统计即可。

    树状数组优化即可,时间复杂度 $O(T imes nlog^2 n imes q)=TLE$ 。

    思考哪步能优化,通过简单思考发现 $S_r-xleq S_{l-1}$ 这个式子 $S$ 是单调递增的,所以直接单调队列优化即可。

    时间复杂度 $O(T imes nlog n imes q)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<climits>
    #include<deque>
    #define LL long long
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=200011;
    int T,a[MAXN],n,q;
    deque<int> Quee;
    namespace force{
        int s[500501];
        LL S[500501];
        inline void Solve(){
            s[0]=0;
            for(int i=1;i<=n;i++) S[i]=S[i-1]+a[i];
            for(int i=1;i<=n;i++)
                for(int j=i;j<=n;j++) s[++s[0]]=S[j]-S[i-1];
            sort(s+1,s+s[0]+1);
            S[0]=0ll;for(int i=1;i<=s[0];i++) S[i]=S[i-1]+(LL)s[i];
            while(q--){
                int l=read(),r=read();
                printf("%lld
    ",S[r]-S[l-1]);
            }
            return;
        }
    }
    namespace std{
        int N,tmp[MAXN<<1];
        LL S[MAXN];
        int a1[MAXN],a2[MAXN],mid,E,tot;
        struct Que{
            int opt,kth,id,L;
             LL ans;
        }que[41];
        inline int Q(int x){
            while(!Quee.empty()) Quee.pop_back();
            int Ans=0;
            for(int i=1;i<=n;i++) a1[i]=S[i],a2[i]=S[i]-x;
            Quee.push_back(0);
            for(int i=1;i<=n;i++){
                while(!Quee.empty()){
                    if(Quee.front()<a2[i]) Quee.pop_front();
                    else break;
                }
                Ans+=Quee.size();
                Quee.push_back(a1[i]);
            }return Ans;
        }
        inline LL Qsum(int x){
            while(!Quee.empty()) Quee.pop_back();
            int Ans=0;
            for(int i=1;i<=n;i++) a1[i]=S[i],a2[i]=S[i]-x;
            int Sum=0;
            Quee.push_back(0);
            for(int i=1;i<=n;i++){
                while(!Quee.empty()){
                    if(Quee.front()<a2[i]) Sum-=Quee.front(),Quee.pop_front();
                    else break;
                }
                Ans+=Quee.size()*a1[i]-Sum;
                Quee.push_back(a1[i]);Sum+=a1[i];
            }return Ans;
        }
        inline LL Query(int x,int id){
            if(!x) return 0;
            int l=que[id-1].L,r=INT_MAX,Minn=INT_MAX,K;
            while(l<=r){
                mid=l+r>>1;
                E=Q(mid);
                if(E>=x){K=E;Minn=mid,r=mid-1;}
                else l=mid+1;
            }
            que[id].L=Minn;
            int Num1=K;
            return (LL)Qsum(Minn)-(Num1-x)*Minn;
        }
        bool cmp1(Que x1,Que x2){return x1.kth<x2.kth;}
        bool cmp(Que x1,Que x2){
            if(x1.id==x2.id) return x1.opt<x2.opt;
            return x1.id<x2.id;
        }
        inline void Solve(){
            tot=0;S[0]=0;
            for(int i=1;i<=n;i++) S[i]=S[i-1]+a[i];
            for(int i=1;i<=q;i++) que[++tot].opt=-1,que[tot].kth=read()-1,que[++tot].opt=1,que[tot].kth=read(),que[tot].id=que[tot-1].id=i;
            sort(que,que+tot+1,cmp1);
            que[0].ans=0ll;
            for(int i=1;i<=tot;i++) que[i].ans=Query(que[i].kth,i);
            sort(que,que+tot+1,cmp);
            for(int i=2;i<=tot;i+=2) printf("%lld
    ",que[i].ans-que[i-1].ans);return;
        }
    }
    void solve(){
        n=read(),q=read();
        for(int i=1;i<=n;i++) a[i]=read();
        if(n<=1000){force::Solve();return;}
        std::Solve();return;
    }
    signed main(){
        freopen("sum.in","r",stdin);
        freopen("sum.out","w",stdout);
        T=read();
        while(T--) solve();
    }
    View Code

    安全路径

    题意简述

    给定一棵有 $n$ 个点的树,每条边有颜色。

    求满足条件的三元组 $(u,v,w)$ ,满足 $u-v,u-w,v-w$ 之间都有红边经过。

    $solution:$

    想过容斥原理,但是没有想到可以这么草率。

    通过容斥原理我们可以简单的将问题转化为求至少要一对只能走蓝边到达。

    我们将只能用蓝边互相到达的放到一个连通块中,设当前考虑的联通块为 $i$ ,其里面数量为 $g$ 。

    则 $Ans=dbinom{n}{3}-sum_{i=1} dbinom{g}{3}+(n-g) imes dbinom{g}{2}$ 。

    时间复杂度 $O(n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<climits>
    #define int long long
    #define mod 1000000007
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=1000001;
    int Inv[MAXN],fac[MAXN],Infac[MAXN];
    void init(){
        fac[0]=1;for(int i=1;i<MAXN;i++) fac[i]=fac[i-1]*i,fac[i]%=mod;
        Inv[1]=1;for(int i=2;i<MAXN;i++) Inv[i]=((mod-mod/i)*Inv[mod%i])%mod;
        Infac[0]=1;for(int i=1;i<MAXN;i++) Infac[i]=Infac[i-1]*Inv[i],Infac[i]%=mod;
        return;
    }
    int n;
    char str[MAXN];
    struct node{
        int u,v,w,nex;
    }x[MAXN<<1];
    int col[MAXN],head[MAXN],cnt,Num[MAXN];
    void add(int u,int v,int w){
        x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
    }
    int C(int a,int b){
        if(a<b) return 0;
        return (((fac[a]*Infac[b])%mod)*Infac[a-b])%mod;
    }
    void dfs(int u,int fath,int id){
        col[u]=id;
        for(int i=head[u];i!=-1;i=x[i].nex){
            if(x[i].v==fath) continue;
            if(x[i].w==1) continue;
            dfs(x[i].v,u,id);
        }return;
    }
    int Mod(int x){return ((x%mod)+mod)%mod;}
    signed main(){
        freopen("path.in","r",stdin);
        freopen("path.out","w",stdout);
        memset(head,-1,sizeof(head));init();
        n=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read(),w;
            scanf("%s",str+1);
            if(str[1]=='b') w=0;else w=1;
            add(u,v,w),add(v,u,w);
        }
        for(int i=1;i<=n;i++) if(!col[i]) dfs(i,0,++col[0]);
        for(int i=1;i<=n;i++) Num[col[i]]++;
        int Ans=0;
        for(int i=1;i<=col[0];i++) Ans+=C(Num[i],3),Ans%=mod;
        for(int i=1;i<=col[0];i++) Ans+=C(Num[i],2)*(n-Num[i]),Ans%=mod;
        printf("%lld
    ",Mod(C(n,3)-Ans));
    }
    View Code

    小朋友的笑话

     link

    $solution:$

    题目告诉了我们说听过 $i$ 号笑话的人再听也不会在笑。

    考虑同 $set$ 维护当前听过故事的人,每次只要将要加入的 $l,r$ 与 $set$ 中的元素查交集即可,因为每次将有交集的和为一个整体保证了每个信息只会最多出现两次。

    利用线段树维护区间赋值。

    时间复杂度 $O(nlog n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<climits>
    #include<set>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=200001;
    struct Segment{
        int tag[MAXN<<2],sum[MAXN<<2];
        void init(){memset(tag,-1,sizeof(tag));}
        void pushdown(int k,int l,int r){
            int mid=l+r>>1;
            sum[k<<1]=(mid-l+1)*tag[k],sum[k<<1|1]=(r-mid)*tag[k];
            tag[k<<1]=tag[k],tag[k<<1|1]=tag[k];
            tag[k]=-1;return;
        }
        void Modify(int k,int l,int r,int x,int y,int w){
            if(x<=l&&r<=y){
                sum[k]=(r-l+1)*w;
                tag[k]=w;return;
            }
            if(tag[k]!=-1) pushdown(k,l,r);
            int mid=l+r>>1;
            if(x<=mid) Modify(k<<1,l,mid,x,y,w);
            if(mid<y) Modify(k<<1|1,mid+1,r,x,y,w);
            sum[k]=sum[k<<1]+sum[k<<1|1];
            return;
        }
        int Query(int k,int l,int r,int x,int y){
            if(x<=l&&r<=y) return sum[k];
            if(tag[k]!=-1) pushdown(k,l,r);
            int mid=l+r>>1,res=0;
            if(x<=mid) res+=Query(k<<1,l,mid,x,y);
            if(mid<y) res+=Query(k<<1|1,mid+1,r,x,y);
            sum[k]=sum[k<<1]+sum[k<<1|1];return res;
        }
    }segment;
    int n,m;
    set<pair<int,int> > s[MAXN];
    set<pair<int,int> > ::iterator it,it1;
    void Modify(int x,int id,int k){
        int L=max(1,x-k),R=min(n,x+k);
        if(s[id].empty()){
            segment.Modify(1,1,n,L,R,1);
            s[id].insert(make_pair(L,R));return;
        }
        it=s[id].lower_bound(make_pair(L,0));
        if(it!=s[id].begin()){
            it--;
            if(it->second<L) it++;
        }
        if(it==s[id].end()){
            segment.Modify(1,1,n,L,R,1);
            s[id].insert(make_pair(L,R));return;
        }
        segment.Modify(1,1,n,L,R,1);
        int nowl=min(L,it->first),nowr=R;
        while(it!=s[id].end()&&it->first<=R){
            nowr=max(nowr,it->second);
            segment.Modify(1,1,n,max(L,it->first),min(R,it->second),0);
            it1=it;
            it++;
            s[id].erase(it1);
        }
        s[id].insert(make_pair(nowl,nowr));return;
    }
    int main(){
        freopen("joke.in","r",stdin);
        freopen("joke.out","w",stdout);
        segment.init();
        n=read(),m=read();
        for(int i=1;i<=m;i++){
            int opt=read();
            if(opt==1){
                int x=read(),id=read(),k=read();
                Modify(x,id,k);
                
            }else{
                int l=read(),r=read();
                printf("%d
    ",segment.Query(1,1,n,l,r));
            }
        }return 0;
    }
    View Code
  • 相关阅读:
    Code-EncryptDecrypt:DES
    Code-Helper:EncryptHelper.cs
    Code-Helper:EmailHelper.cs
    养生-影视:《长寿之道——长寿村里的百岁夫妻》
    影视-栏目:《致富经》
    影视-栏目:《远方的家》
    影视-纪录片:《长江行》
    影视-纪录片:《塔里木河》
    影视-纪录片:《天山脚下》
    Counting Lines, Words, and Characters with wc
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/11321453.html
Copyright © 2011-2022 走看看