2018.9.12 离线赛 by CalvinJin

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

T1——gcd(3915)

Description:

给你两个数 A , B ,求 gcd ( A n + B n , A B ) m o d ( 10 9 + 7 ) .特殊地, gcd ( 0 , x ) = x .
A , B , n 10 18 , B A

Solution:

  • 关于此题,不知道是被题面误导要因式分解,还是被NOIP2017D1T1所敏感地去打表…
  • 反正一开始就没想到正解上,接近自闭…
  • 但当开始走投无路的去肉模拟这个玩意的时候 gcd ( A n + B n , A B ) ,发现推了一次得到 gcd ( A B , ( A n + B n ) m o d ( A B ) ) ,就感觉这个好像就是将 g c d 肉拆一次,再次 g c d
  • 真的无语…有点脑筋急转弯的味道…

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
    x=0;char c;
    while((c=getchar())<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while((c=getchar())>47);
}

#define mod 1000000007

ll A,B,K;

ll gcd(ll x,ll y){return !y?x:gcd(y,x%y);}

struct p50{
    ll Pow(ll a,ll b){
        ll x=1;
        while(b){
            if(b&1)x=x*a%mod;
            b>>=1,a=a*a%mod;
        }
        return x;
    }

    void solve(){
        ll X=A-B;
        ll Y=Pow(A,K)+Pow(B,K);
        if(!X)printf("%lld\n",Y%mod);
        else {
            ll d=gcd(X,Y)%mod;
            printf("%lld\n",d);
        }
    }
}p1;

struct p100{

    ll Mul(ll x,ll y,ll P){
        ll res=0;
        while(y){
            if(y&1)res=(res+x)%P;
            y>>=1;
            x=(x<<1)%P;
        }
        return res;
    }

    ll Pow(ll a,ll b,ll P){
        ll x=1;
        while(b){
            if(b&1)x=Mul(x,a,P);
            a=Mul(a,a,P);
            b>>=1;
        }
        return x;
    }

    void solve(){
        ll X=A-B;
        if(!X)printf("%lld\n",(Pow(A,K,mod)+Pow(B,K,mod))%mod);
        else {
            ll Y=(Pow(A,K,X)+Pow(B,K,X))%X;
            printf("%lld\n",gcd(X,Y)%mod);
        }
    }
}p2;

int main(){

//  freopen("gcd.in","r",stdin);
//  freopen("gcd.out","w",stdout);

    Rd(A),Rd(B),Rd(K);

    if(A<=9 && B<=9 && K<=9)p1.solve();
    else p2.solve();

    return 0;
}

T2——triangle(3916)

Description:

有一个长度为 n 的序列{ A },表示木棒的长度.我们将用这些木棒拼出周长最大的三角形.
那么有 q 个操作.

  1. o p = 1 , p o s , v a l .将 A p o s = v a l
  2. o p = 2 ,l,r.对区间 [ l , r ] 进行询问最大的三角形周长.
    n , q 10 5 , A i 10 9

Solution:

  • 对于三角形的周长问题,最近也是频繁遇到.
  • 而此题是带单点修改的.那么显然是用线段树解决.
  • 那么线段树的关键还是合并问题.
  • 我们发现,在树上直接存答案是不太现实的.
  • 那么我们只能是存该区间的一些木棒.
  • 而我们要的是最大的周长,那么关键字一定是 > .
  • 这里,我觉得自己的做法还是偏无脑的做法.
  • 因为分析修改的 q ,对于每个区间影响的 A i ,其实是只有 log q 个.
  • 那么我们就在树上存上每个区间的前 log q A i 即可.
  • 最后询问暴力来取 m a x .

Code:

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast")
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(l) sizeof(l)
#define mcl(l,b) memset(l,b,Sz(l))
#define mcp(l,b) memcpy(l,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
    x=0;char c;
    while((c=getchar())<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while((c=getchar())>47);
}

#define N 100002

int n,q;
int A[N];

struct p40{

    int tmp[N],cnt;

    void solve(){
        int op,a,b;
        ll ans;
        while(q--){
            Rd(op),Rd(a),Rd(b);
            if(op==1)A[a]=b;
            else {
                cnt=0;
                REP(i,a,b)tmp[++cnt]=A[i];
                sort(tmp+1,tmp+1+cnt);

                ans=0;
                REP(i,1,cnt-2){
                    REP(j,i+1,cnt-1){
                        int k=lower_bound(tmp+j+1,tmp+cnt+1,tmp[j])-tmp;
                        if(tmp[i]+tmp[j]>tmp[k])chkmax(ans,(ll)tmp[i]+tmp[j]+tmp[k]);
                    }
                }

                printf("%lld\n",ans);
            }                       
        }
    }
}p1;

struct p100{

    #define lson L,mid,p<<1
    #define rson mid+1,R,p<<1|1

    struct node{
        int L,R;
        int len,l[50];
    }tree[N<<2],ans;

    node Up(node L,node R){
        node res;
        res.L=L.L,res.R=R.R;
        res.len=min(47,L.len+R.len);

        int p1=1,p2=1;
        REP(i,1,res.len){
            if(p1<=L.len && p2<=R.len) res.l[i]=(L.l[p1]>R.l[p2]?L.l[p1++]:R.l[p2++]);
            else if(p1<=L.len)res.l[i]=L.l[p1++];
            else res.l[i]=R.l[p2++];
        }
        return res;
    }

    void build(int L,int R,int p){
        tree[p].L=L,tree[p].R=R;
        if(L==R){
            tree[p].len=1;
            tree[p].l[1]=A[L];
            return;
        }
        int mid=(L+R)>>1;
        build(lson),build(rson);
        tree[p]=Up(tree[p<<1],tree[p<<1|1]);
    }

    void update(int p,int x,int v){
        if(tree[p].L==tree[p].R){
            tree[p].l[1]=v;
            return;
        }
        int mid=(tree[p].L+tree[p].R)>>1;
        if(x<=mid)update(p<<1,x,v);
        else update(p<<1|1,x,v);
        tree[p]=Up(tree[p<<1],tree[p<<1|1]);
    }

    node query(int L,int R,int p){
        if(tree[p].L==L && tree[p].R==R)return tree[p];
        int mid=(tree[p].L+tree[p].R)>>1;
        if(R<=mid)return query(L,R,p<<1);
        else if(L>mid)return query(L,R,p<<1|1);
        else return Up(query(lson),query(rson));
    }

    void solve(){
        build(1,n,1);
        int op,a,b;
        while(q--){
            Rd(op),Rd(a),Rd(b);
            if(op==1)update(1,a,b);
            else {
                ans=query(a,b,1);
                ll res=0;
                REP(i,3,ans.len) if(ans.l[i]+ans.l[i-1]>ans.l[i-2]) chkmax(res,1ll*ans.l[i]+ans.l[i-1]+ans.l[i-2]);
                printf("%lld\n",res);
            }
        }
    }
}p2;

int main(){

//  freopen("triangle.in","r",stdin);
//  freopen("triangle.out","w",stdout);

    Rd(n),Rd(q);
    REP(i,1,n)Rd(A[i]);

    if(n<=100 && q<=100)p1.solve();
    else p2.solve();

    return 0;
}

T3——cactus(3916)

Description:

给出 n 个点, m 条边的仅存在简单环的图.求对于每个点,删掉 m n + 1 条边(即变为一棵树)后的到其它点的最大值的最小值.
n 500000

Solution:

  • 对于题面一上来就仙人掌的…表示很虚啊..
  • 但是切完分,发现暴力+图本为一棵树的解法差不多就是正解了吧…
  • 只不过这里存在简单环.我们先tarjan缩点.这里我顺便就用了圆方树.
  • 那么缩点后其实还是一棵树.
  • 但是对于要经过环的答案.意义就在于环上的距离的计算.
  • 我们不难模拟发现,对于环上的每个点,删掉它的对立的那条边是最优的.
  • 即对于环上的每个点.它的最大距离其实就是该点顺时针和逆时针走到对立边的最大值.
  • 而这个最大值,我们可以给它依次编号,那么环上两点的距离就是编号差了.
  • 但是对于这个 n 的范围,我们只能线性来做,而枚举两点的复杂度显然是炸的….
  • 进一步分析,对于一个环,我们只能以当前点到其它点的距离以及答案传到它的子树下,再在它的子树下统计答案.
  • 这里,环上的距离我们不难发现就是维护一个单调队列,这是可以做到 Θ ( n ) 的.
  • 此题虽然解法简单,但它的实现难度着实脑壳疼啊…

Code:

#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t)for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t)for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t)for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define db double
#define ll long long 
#define INF 0x3f3f3f3f
#define inf 0x3f3f3f3f3f3f3f
#define MINF 0xc0c0c0c0
#define Sz(a) sizeof(a)
#define mcl(a,b) memset(a,b,Sz(a))
#define mcp(a,b) memcpy(a,b,Sz(b))
#define pb push_back
#define fi first
#define se second
template<class T>inline bool chkmin(T &x,T y){return y<x?x=y,1:0;}
template<class T>inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
typedef pair<int,int>PII;
template<class T>inline void Rd(T &x){
    x=0;char c;
    while((c=getchar())<48);
    do x=(x<<1)+(x<<3)+(c^48);
    while((c=getchar())>47);
}

#define N 1000002

int n,m;
int qwq,head[N];
struct edge{
    int to,nxt;
}E[N<<1];
inline void addedge(int x,int y){E[qwq]=(edge){y,head[x]};head[x]=qwq++;}
#define LREP(x) for(int i=head[x];~i;i=E[i].nxt)

struct p30{

    int dis[2002];
    bool vis[2002];
    queue<int>Q;

    void SPFA(int s){
        mcl(dis,INF);

        Q.push(s);
        vis[s]=1;
        dis[s]=0;

        while(!Q.empty()){
            int x=Q.front();Q.pop();
            vis[x]=0;
            LREP(x){
                int y=E[i].to;
                if(chkmin(dis[y],dis[x]+1)){
                    if(!vis[y]){
                        vis[y]=1;
                        Q.push(y);
                    }
                }
            }       
        }

    }

    void solve(){

        int ans;
        REP(i,1,n){
            SPFA(i);
            ans=0;
            REP(j,1,n)chkmax(ans,dis[j]);
            printf("%d\n",ans);
        }

    }
}p1;

struct p50{

    int f[500002][2],g[500002][2];

    int max2(int a,int b,int c) {
        if((a>=b&&a<=c)||(a<=b&&a>=c))  return a;
        if((b<=a&&b>=c)||(b<=c&&b>=a))  return b;
        return c;
    }

    void dfs1(int x,int fa) {
        LREP(x){
            int y=E[i].to;
            if(y==fa)continue;
            dfs1(y,x);
            chkmax(g[x][1],g[y][0]+1);
            if(g[x][0]<g[x][1])swap(g[x][0],g[x][1]);
        }
    }

    void dfs2(int x,int fa) {
        LREP(x){
            int y=E[i].to;
            if(y==fa)continue;
            if(f[x][0]!=g[y][0]+1) {
                f[y][0]=f[x][0]+1;
                f[y][1]=g[x][0];
            } 
            else {
                f[y][0]=max(g[y][0],f[x][1]+1);
                f[y][1]=max2(g[y][0],g[y][1],f[x][1]+1);
            }
            dfs2(y,x);
        }
    }

    void solve(){

        dfs1(1,0);
        f[1][0]=g[1][0];
        f[1][1]=g[1][1];
        dfs2(1,0);

        REP(i,1,n)printf("%d\n",f[i][0]);
    }
}p2;

struct p100{

    int dfn[N],low[N],tim;
    int stk[N],top;
    bool vis[N];

    int tot;
    bool mark[N<<1];
    int degree[N<<1];

    int qaq,Head[N<<1];
    struct Edge{
        int to,nxt;
    }G[N<<2];
    void Addedge(int x,int y){
        G[qaq]=(Edge){y,Head[x]};
        Head[x]=qaq++;
        ++degree[x];
    }
    #define GREP(x) for(int i=Head[x];~i;i=G[i].nxt)

    int f[N<<1],g[N<<1];
    int sec[N<<1],son[N<<1];

    void tarjan(int x,int f){
        dfn[x]=low[x]=++tim;
        vis[x]=1;
        stk[++top]=x; 
        bool flag=0;

        LREP(x){
            int y=E[i].to;
            if(y==f && !flag){flag=1;continue;}
            if(!dfn[y]){
                tarjan(y,x);
                if(low[y]>dfn[x]){
                    Addedge(x,y),Addedge(y,x);
                    top--;
                }
                if(low[y]==dfn[x]){
                    mark[++tot]=1;
                    Addedge(x,tot),Addedge(tot,x);
                    do Addedge(tot,stk[top]),Addedge(stk[top],tot);
                    while(y!=stk[top--]);
                }
                chkmin(low[x],low[y]);
            }
            else if(vis[y])chkmin(low[x],dfn[y]);
        }
    }

    int dist(int x,int y,int len){
        return min(x-y,y-x+len);
    }

    void loop1(int x,int fa){
        int len=degree[x],id=0;
        GREP(x){
            id++;
            int y=G[i].to;
            if(y!=fa) chkmax(f[x],f[y]+dist(len,id,len));
        }
        f[x]--;
    }   

    void dfs1(int x,int fa){
        GREP(x){
            int y=G[i].to;
            if(y==fa)continue;
            dfs1(y,x);
            if(!mark[x]){
                if(f[x]<f[y]+1){
                    sec[x]=f[x];
                    f[x]=f[y]+1;
                    son[x]=y;
                }
                else chkmax(sec[x],f[y]+1);
            }
        }
        if(mark[x])loop1(x,fa);
    }

    struct Queue {
        int q[N<<2],id[N<<2],L,R;
        void init(){L=1;R=0;}
        void push(int x,int pos){
            while (x>q[R] && L<=R)R--;
            q[++R]=x;
            id[R]=pos;
        }
        int top(){return q[L];}
        int pos(){return id[L];}
        void valid(int x) {while (L<=R && id[L]<x)L++;}
        bool empty(){return R<L;}
    }Q;
    int tmp[N<<2];

    void loop2(int x,int fa){
        g[x]--;
        int len=degree[x],id=0;
        Q.init();
        GREP(x){
            int y=G[i].to;
            tmp[++id]=y;
            Q.valid(id-len/2);
            if(y!=fa && !Q.empty()) chkmax(g[y],Q.top()+id);
            if(y!=fa) Q.push(f[y]-id,id);
            else Q.push(g[x]-id,id);
        }
        GREP(x){
            int y=G[i].to;
            tmp[++id]=y;
            Q.valid(id-len/2);
            if(y!=fa && !Q.empty()) chkmax(g[y],Q.top()+id);
            if(y!=fa) Q.push(f[y]-id,id);
            else Q.push(g[x]-id,id);
        }
        Q.init();
        DREP(i,id,1){
            Q.valid(-i-len/2);
            if(tmp[i]!=fa && !Q.empty()) chkmax(g[tmp[i]],Q.top()-i);
            if(tmp[i]!=fa) Q.push(f[tmp[i]]+i,-i);
            else Q.push(g[x]+i,-i);
        }
    }

    void dfs2(int x,int fa){
        if(mark[x])loop2(x,fa);
        GREP(x){
            int y=G[i].to;
            if(y==fa)continue;
            if(!mark[x]){
                chkmax(g[y],g[x]+1);
                if(son[x]!=y)chkmax(g[y],f[x]+1);
                else chkmax(g[y],sec[x]+1);
            }
            dfs2(y,x);
        }
        chkmax(g[x],f[x]);
    }

    void solve(){

        tot=n;
        qaq=0;
        mcl(Head,-1);

        REP(i,1,n) if(!dfn[i]) tarjan(i,0);
        dfs1(1,0);
        dfs2(1,0);

        REP(i,1,n) printf("%d\n",g[i]);
    }
}p3;

int main(){
//  freopen("cactus.in","r",stdin);
//  freopen("cactus.out","w",stdout);

    qwq=0;
    mcl(head,-1);

    Rd(n),Rd(m);
    REP(i,1,m){
        int a,b;
        Rd(a),Rd(b);
        addedge(a,b);
        addedge(b,a);
    }

    if(n==m+1)p2.solve();
    else if(n<=2000)p1.solve();
    else p3.solve();

    return 0;
}

Summary:

  • T 1 的思维难度着实蛋疼…但也不妨是一种套路…
  • T 2 还是一道比较正常的线段树,虽然不是 N O I P 范围内.
  • T 3 是真毒瘤…实现难度奇大无比…细节超多…但题型还是比较正常的..
  • 综上,题目都是中等偏难的,就是 T 3 的码量也是大得不要不要的…
  • 评价:较毒瘤出题人.

猜你喜欢

转载自blog.csdn.net/Caristra/article/details/82693698
今日推荐