2018.9.12 离线赛 by CalvinJin

T1——gcd(3915)

Description:

给你两个数 A A ,B,求 gcd(An+Bn,AB)mod(109+7) gcd ( A n + B n , A − B ) m o d ( 10 9 + 7 ) .特殊地, gcd(0,x)=x gcd ( 0 , x ) = x .
A,B,n1018,BA A , B , n ≤ 10 18 , B ≤ A

Solution:

  • 关于此题,不知道是被题面误导要因式分解,还是被NOIP2017D1T1所敏感地去打表…
  • 反正一开始就没想到正解上,接近自闭…
  • 但当开始走投无路的去肉模拟这个玩意的时候 gcd(An+Bn,AB) gcd ( A n + B n , A − B ) ,发现推了一次得到 gcd(AB,(An+Bn)mod(AB)) gcd ( A − B , ( A n + B n ) m o d ( A − B ) ) ,就感觉这个好像就是将 gcd g c d 肉拆一次,再次 gcd 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 n 的序列{A},表示木棒的长度.我们将用这些木棒拼出周长最大的三角形.
那么有 q q 个操作.

  1. op=1, pos p o s , val v a l .将 Apos=val A p o s = v a l

    • op=2 o p = 2 ,l,r.对区间 [l,r] [ l , r ] 进行询问最大的三角形周长.
      n,q105,Ai109 n , q ≤ 10 5 , A i ≤ 10 9
    • Solution:

      • 对于三角形的周长问题,最近也是频繁遇到.
      • 而此题是带单点修改的.那么显然是用线段树解决.
      • 那么线段树的关键还是合并问题.
      • 我们发现,在树上直接存答案是不太现实的.
      • 那么我们只能是存该区间的一些木棒.
      • 而我们要的是最大的周长,那么关键字一定是 > > .
      • 这里,我觉得自己的做法还是偏无脑的做法.
      • 因为分析修改的q,对于每个区间影响的 Ai A i ,其实是只有 logq log ⁡ q 个.
      • 那么我们就在树上存上每个区间的前 logq log ⁡ q Ai A i 即可.
      • 最后询问暴力来取 max 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 n 个点,m条边的仅存在简单环的图.求对于每个点,删掉 mn+1 m − n + 1 条边(即变为一棵树)后的到其它点的最大值的最小值.
      n500000 n ≤ 500000

      Solution:

      • 对于题面一上来就仙人掌的…表示很虚啊..
      • 但是切完分,发现暴力+图本为一棵树的解法差不多就是正解了吧…
      • 只不过这里存在简单环.我们先tarjan缩点.这里我顺便就用了圆方树.
      • 那么缩点后其实还是一棵树.
      • 但是对于要经过环的答案.意义就在于环上的距离的计算.
      • 我们不难模拟发现,对于环上的每个点,删掉它的对立的那条边是最优的.
      • 即对于环上的每个点.它的最大距离其实就是该点顺时针和逆时针走到对立边的最大值.
      • 而这个最大值,我们可以给它依次编号,那么环上两点的距离就是编号差了.
      • 但是对于这个 n 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:

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值