<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Potyczki Algorytmiczne 2011

      Trial Round:

      Tulips

      按題意模擬。

      #include<cstdio>
      const int N=15000;
      int n,ans=N,x,v[N+1];
      int main(){
        scanf("%d",&n);
        while(n--){
          scanf("%d",&x);
          if(!v[x])ans--,v[x]=1;
        }
        printf("%d",ans);
      }
      

        

      Round 1:

      Rooks [B]

      對于每個沒有車的行,隨便找一個沒有車的列配對。

      #include<cstdio>
      const int N=1005;
      int n,i,j,a[N],b[N];char tmp[N];
      int main(){
        scanf("%d",&n);
        for(i=1;i<=n;i++){
          scanf("%s",tmp+1);
          for(j=1;j<=n;j++)if(tmp[j]=='W')b[a[i]=j]=1;
        }
        for(i=1;i<=n;i++)if(!a[i])for(j=1;j<=n;j++)if(!b[j]){b[a[i]=j]=1;break;}
        for(i=1;i<=n;i++){
          for(j=1;j<=n;j++)tmp[j]='.';
          tmp[a[i]]='W';
          puts(tmp+1);
        }
      }
      

        

      Round 2:

      Unlucky [A]

      如果$w$不是$k$的倍數,那么先考慮從起點帶$w\bmod k$升水出發怎么處理,然后再依次考慮每次從起點帶$k$升水出發怎么處理。

      假設目前已經推進到的右端點是$all$,算上這次一共要從起點出發$t$次,那么從$all$往右推進的這段路將被經過總計$2t-1$次。最優策略是將這次出發帶走的水平均分成$2t-1$份,從而得到本次推進的距離,注意距離要和到終點的距離取$\min$。

      求出推進距離后,乘以經過的次數,就是這段路消耗的水量。

      時間復雜度$O(\frac{w}{k})$。

      #include<cstdio>
      typedef double db;
      int s,w,k,o;db sum,all;
      inline void gao(db k){
        k/=o;
        if(k+all>=s)k=s-all;
        sum+=k*o;
        all+=k;
        o-=2;
      }
      int main(){
        scanf("%d%d%d",&s,&w,&k);
        o=(w/k)*2-1;
        if(w%k)o+=2,gao(w%k);
        while(o>0)gao(k);
        printf("%.3f",w-sum);
      }
      

        

      Climbing [B]

      從左往右貪心,若一段區間能拼上則拼上,通過維護關于最左邊數的不等式組的解集來判斷。

      時間復雜度$O(n)$。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      typedef long long ll;
      int n,i,ans,A,B;ll L,R,C,D;
      inline bool check(ll K){
        if(C==1){
          L=max(L,-D);
          R=min(R,K-D);
        }else{
          L=max(L,D-K);
          R=min(R,D);
        }
        return L<=R;
      }
      int main(){
        scanf("%d",&n);
        for(i=1;i<=n;i++){
          scanf("%d%d",&A,&B);
          A+=B;
          if(i>1&&check(A)){
            ans++;
            D=A-D;
            C=-C;
          }else{
            L=0,R=A;
            C=-1,D=A;
          }
        }
        printf("%d",ans);
      }
      

        

      Round 3:

      Pedestrian Crossing [B]

      在模$K$意義下做,每個白色段會禁掉起點位置的一個區間,注意這里區間端點不會被禁,所以引入$0.5$坐標。最后檢查是否$[0,K-0.5]$都被禁了即可。

      時間復雜度$O(n\log n)$。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      typedef long long ll;
      typedef pair<ll,ll>P;
      const int N=500005;
      int Case,n,m,i;
      ll S,K,l,r,sum,len[N];
      P e[N<<1];
      inline void ban(ll l,ll r){
        if(l>r)return;
        e[++m]=P(l,r);
      }
      inline bool gao(ll l,ll r){
        if(l+K-S<r)return 0;
        l%=K,r%=K;
        if(l>r)r+=K;
        l+=K-S,r+=K;
        if(l/K==r/K)ban(l%K*2+1,r%K*2-1);
        else{
          ban(l%K*2+1,K*2-1);
          ban(0,r%K*2-1);
        }
        return 1;
      }
      bool check(){
        scanf("%lld%lld%d",&S,&K,&n);
        for(i=1;i<=n;i++)scanf("%lld",&len[i]),len[i]+=len[i-1];
        m=0;
        for(i=1;i<=n;i+=2)if(!gao(len[i-1],len[i]))return 0;
        sort(e+1,e+m+1);
        l=0,r=-5,sum=0;
        for(i=1;i<=m;i++){
          if(e[i].first>r+1){
            if(l<=r)sum+=r-l+1;
            l=e[i].first;
          }
          r=max(r,e[i].second);
        }
        if(l<=r)sum+=r-l+1;
        return sum<K*2;
      }
      int main(){
        scanf("%d",&Case);
        while(Case--)puts(check()?"TAK":"NIE");
      }
      

        

      Round 4:

      Fuel [B]

      找到一條樹直徑,令直徑上的點代價為$1$,剩下的點代價為$2$,注意起點代價為$0$,然后貪心選點即可。

      時間復雜度$O(n)$。

      #include<cstdio>
      const int N=500005;
      int n,m,i,x,y,g[N],v[N<<1],nxt[N<<1],ed,A,B,ans;
      inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
      void dfs(int x,int y,int d){
        if(d>B)A=x,B=d;
        for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x,d+1);
      }
      int main(){
        scanf("%d%d",&n,&m);
        for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
        dfs(1,0,1);
        dfs(A,0,1);
        A=n-B;
        ans=1,B--;
        while(m&&B)m--,B--,ans++;
        while(m>1&&A)m-=2,A--,ans++;
        printf("%d",ans);
      }
      

        

      Round 5:

      Declining Sequences [B]

      求出$f[i][j]$表示有多少以$j$為起點長度為$i$的遞減序列。

      對于一個有解的詢問,從第$1$層一直找到第$m$層,每層需要找到權值小于某數,且下標大于某數的部分里從左往右第$k$個方案所在的下標。

      按照權值掃描線后,線段樹上維護區間$f$值的和,然后在線段樹上二分即可。

      時間復雜度$O(nm\log n)$。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      typedef long long ll;
      const int N=100005,K=13,M=262155;
      const ll inf=1000000000000000010LL;
      int n,m,q,i,j,k,o,a[N],b[N],ans[N][K];ll f[K][N],bit[N],que[N],all;
      int gn[N],gq[N],v[N<<1],nxt[N<<1],ed;
      int pos[N],A,B;ll val[M],C;
      inline void up(ll&a,ll b){a=a+b<inf?a+b:inf;}
      inline void ins(int x,ll p){for(;x<=n;x+=x&-x)up(bit[x],p);}
      inline ll ask(int x){ll t=0;for(;x;x-=x&-x)up(t,bit[x]);return t;}
      inline void add(int&x,int y){v[++ed]=y;nxt[ed]=x;x=ed;}
      void build(int x,int a,int b){
        val[x]=0;
        if(a==b){pos[a]=x;return;}
        int mid=(a+b)>>1;
        build(x<<1,a,mid),build(x<<1|1,mid+1,b);
      }
      inline void modify(int x,ll p){
        val[x=pos[x]]=p;
        for(x>>=1;x;x>>=1)val[x]=val[x<<1],up(val[x],val[x<<1|1]);
      }
      void query(int x,int a,int b){
        if(B)return;
        if(A<=a&&val[x]<C){C-=val[x];return;}
        if(a==b){B=a;return;}
        int mid=(a+b)>>1;
        if(A<=mid)query(x<<1,a,mid);
        query(x<<1|1,mid+1,b);
      }
      int main(){
        scanf("%d%d%d",&n,&m,&q);
        for(i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];
        sort(b+1,b+n+1);
        for(i=1;i<=n;i++)a[i]=lower_bound(b+1,b+n+1,a[i])-b;
        for(i=1;i<=n;i++)f[m][i]=1;
        for(i=m-1;i;i--){
          for(j=1;j<=n;j++)bit[j]=0;
          for(j=n;j;j--){
            f[i][j]=ask(a[j]-1);
            ins(a[j],f[i+1][j]);
          }
        }
        for(i=1;i<=n;i++)up(all,f[1][i]);
        a[0]=n+1;
        for(i=1;i<=q;i++){
          scanf("%lld",&que[i]);
          if(que[i]>all)ans[i][0]=-1;
        }
        for(i=1;i<=n;i++)add(gn[a[i]],i);
        for(i=1;i<=m;i++){
          ed=n;
          for(j=0;j<=n;j++)gq[j]=0;
          for(j=1;j<=q;j++)if(~ans[j][0])add(gq[a[ans[j][i-1]]-1],j);
          build(1,1,n);
          for(j=0;j<=n;j++){
            for(k=gn[j];k;k=nxt[k]){
              o=v[k];
              modify(o,f[i][o]);
            }
            for(k=gq[j];k;k=nxt[k]){
              o=v[k];
              A=ans[o][i-1]+1;
              B=0;
              C=que[o];
              query(1,1,n);
              ans[o][i]=B;
              que[o]=C;
            }
          }
        }
        for(i=1;i<=q;i++){
          if(~ans[i][0])for(j=1;j<=m;j++)printf("%d%c",ans[i][j],j<m?' ':'\n');
          else puts("-1");
        }
      }
      

        

      Double Factorial [B]

      $1!\times 2!\times3!\times\dots\times n!$里質因子$5$的個數即

      \[\left(\lfloor\frac{1}{5^1}\rfloor+\lfloor\frac{2}{5^1}\rfloor+\dots+\lfloor\frac{n}{5^1}\rfloor\right)+\left(\lfloor\frac{1}{5^2}\rfloor+\lfloor\frac{2}{5^2}\rfloor+\dots+\lfloor\frac{n}{5^2}\rfloor\right)+\dots+\left(\lfloor\frac{1}{5^k}\rfloor+\lfloor\frac{2}{5^k}\rfloor+\dots+\lfloor\frac{n}{5^k}\rfloor\right)\]

      枚舉$k$后推公式即可。

      n=int(input())
      ans=0
      k=5
      while k<=n:
        m=n//k
        ans+=(m-1)*m*k//2+m*(n-m*k+1)
        k*=5
      print(ans)
      

        

      Trails [A]

      留坑。

       

      Vacation [A]

      當$k=2$時就是$a$和$b$的距離。

      當$k=3$時,答案上界為$24n$,對于每個點向三個排列對應位置左右$15$個位置連負邊可以減小答案。建立二分圖,使用Dijkstra找增廣路求最小費用流。

      優化1:

      最短路不超過$24$,可以用桶代替堆,使得每次Dijkstra時間復雜度為$O(n+m)$,其中$m=nc$。

      優化2:

      Dijkstra求出源點到每個點的最短路后,在最短路圖上BFS得到每個點的層數。

      沿著最短層進行多路增廣,不斷BFS多路增廣直到無法增廣。

      那么每次Dijkstra求出的最小花費嚴格遞增,且BFS出來的最小層數嚴格遞增。

      沿用Dinic的分析可得每次多路增廣次數不超過$O(\sqrt{n})$,所以一共$O(c\sqrt{n})$次多路增廣。

      總時間復雜度$O(c\sqrt{n}(n+m))$=$O(c^2n^{1.5})$。

      #include<cstdio>
      const int N=5005,inf=10000000,K=30;
      int n,k,i,j,ans,a[N],b[N],c[N],last[N];
      int s,t,cnt=1;
      int g[N<<1],d[N<<1],f[N<<1],vis[N<<1],h[N<<1];
      int pool[K][N<<1],top[K],q[N<<1];
      int cur[N<<1];
      void read(int a[]){
        int i,x;
        for(i=1;i<=n;i++)scanf("%d",&x),a[x]=i;
      }
      inline int abs(int x){return x>0?x:-x;}
      inline int min(int a,int b){return a<b?a:b;}
      struct E{
        int v,f,c,nxt;
        E(){}
        E(int _v,int _f,int _c,int _nxt){v=_v,f=_f,c=_c,nxt=_nxt;}
      }e[N*(15*3+2)*2];
      inline void add(int u,int v,int f,int c){
        e[++cnt]=E(v,f,c,g[u]);
        g[u]=cnt;
        e[++cnt]=E(u,0,-c,g[v]);
        g[v]=cnt;
      }
      inline void addedge(int x,int y){
        if(y<1||y>n)return;
        if(last[y]==x)return;
        last[y]=x;
        int w=min(abs(y-a[x]),8)+min(abs(y-b[x]),8)+min(abs(y-c[x]),8);
        add(x,y+n,1,w-24);
      }
      inline void ext(int x,int y){
        if(y>=K)return;
        d[x]=y;
        pool[y][++top[y]]=x;
      }
      inline bool dijkstra(){
        int i,o;
        for(i=1;i<=t;i++)d[i]=inf,vis[i]=0;
        for(i=0;i<K;i++)top[i]=0;
        ext(s,0);
        for(o=0;o<K;o++)while(top[o]){
          int u=pool[o][top[o]--];
          if(vis[u])continue;
          vis[u]=1;
          for(i=g[u];i;i=e[i].nxt)if(e[i].f){
            int v=e[i].v,w=e[i].c+h[u]-h[v];
            if(d[v]>d[u]+w&&!vis[v])ext(v,d[u]+w);
          }
        }
        return d[t]!=inf;
      }
      inline bool bfs(){
        int head=1,tail=1,i,u,v,z;
        for(i=1;i<=t;i++)vis[i]=0;
        vis[s]=1;
        f[s]=0;
        q[1]=s;
        while(head<=tail){
          u=q[head++];
          z=f[u]+1;
          for(i=g[u];i;i=e[i].nxt)if(e[i].f){
            int v=e[i].v,w=e[i].c+h[u]-h[v];
            if(d[v]==d[u]+w&&!vis[v]){
              vis[v]=1;
              f[v]=z;
              q[++tail]=v;
            }
          }
        }
        return vis[t];
      }
      bool dfs(int u){
        if(u==t)return 1;
        vis[u]=1;
        for(int&i=cur[u];i;i=e[i].nxt){
          int v=e[i].v;
          if(!vis[v]&&e[i].f&&d[v]==d[u]+e[i].c+h[u]-h[v]&&f[v]==f[u]+1){
            int tmp=dfs(v);
            if(tmp){
              ans+=e[i].c;
              e[i].f--,e[i^1].f++;
              vis[u]=0;
              i=e[i].nxt;
              return 1;
            }
          }
        }
        return vis[u]=0;
      }
      int main(){
        scanf("%d%d",&n,&k);
        read(a);
        read(b);
        if(k==2){
          for(i=1;i<=n;i++)ans+=min(abs(a[i]-b[i]),8);
          return printf("%d",ans),0;
        }
        read(c);
        s=n*2+1;
        t=s+1;
        for(i=1;i<=n;i++)add(s,i,1,0),add(i+n,t,1,0);
        for(i=1;i<=n;i++){
          for(j=a[i]-7;j<=a[i]+7;j++)addedge(i,j);
          for(j=b[i]-7;j<=b[i]+7;j++)addedge(i,j);
          for(j=c[i]-7;j<=c[i]+7;j++)addedge(i,j);
        }
        for(i=1;i<=n;i++)for(j=g[i];j;j=e[j].nxt)h[e[j].v]=min(h[e[j].v],e[j].c);
        for(i=1;i<=n;i++)h[t]=min(h[t],h[i+n]);
        ans=n*24;
        while(dijkstra()){
          if(h[t]+d[t]>=0)break;
          while(bfs()){
            for(i=1;i<=t;i++)cur[i]=g[i],vis[i]=0;
            while(dfs(s));
          }
          for(i=1;i<=t;i++)h[i]+=d[i];
        }
        printf("%d",ans);
      }
      

        

      Round 6:

      Automorphisms [B]

      找重心作為根,如果兩個重心就拆了中間加個點作為根。

      對于每個點,將兒子按hash值分組,對于每組,將答案乘以兒子數的階乘即可。

      #include<cstdio>
      #include<vector>
      #include<algorithm>
      #include<map>
      using namespace std;
      typedef vector<int>V;
      const int N=500005,P=1000000007;
      int n,m,cnt,i,x,y,A,B,ans,g[N],v[N<<1],nxt[N<<1],ed,fac[N],sz[N],f[N],q[N];
      V tmp;map<V,int>T;
      inline void add(int x,int y){v[++ed]=y;nxt[ed]=g[x];g[x]=ed;}
      void dfs(int x,int y){
        sz[x]=1;
        for(int i=g[x];i;i=nxt[i])if(v[i]!=y)dfs(v[i],x),sz[x]+=sz[v[i]];
        if(sz[x]>n-sz[x]&&!A)A=x;
        if(sz[x]==n-sz[x])A=x,B=y;
      }
      void cal(int x,int y){
        for(int i=g[x];i;i=nxt[i]){
          int u=v[i];
          if(u==y)continue;
          cal(u,x);
        }
        cnt=0;
        for(int i=g[x];i;i=nxt[i]){
          int u=v[i];
          if(u==y)continue;
          q[cnt++]=f[u];
        }
        sort(q,q+cnt);
        for(int i=0,j;i<cnt;i=j){
          for(j=i;j<cnt&&q[i]==q[j];j++);
          ans=1LL*ans*fac[j-i]%P;
        }
        tmp.resize(cnt);
        for(int i=0;i<cnt;i++)tmp[i]=q[i];
        int&o=T[tmp];
        if(!o)o=++m;
        f[x]=o;
      }
      int main(){
        scanf("%d",&n);
        for(i=1;i<n;i++)scanf("%d%d",&x,&y),add(x,y),add(y,x);
        for(fac[0]=i=1;i<=n;i++)fac[i]=1LL*fac[i-1]*i%P;
        dfs(1,0);
        ans=1;
        cal(A,B);
        if(B){
          cal(B,A);
          if(f[A]==f[B])ans=ans*2%P;
        }
        printf("%d",ans);
      }
      

        

      Kangaroos [A]

      兩個區間$[x_1,y_1][x_2,y_2]$相交等價于$x_1\leq y_2$且$y_1\geq x_2$。

      考慮離線,把所有區間看成二維的點建立K-D Tree。

      然后從$1$到$n$依次加入每個區間,每次加入一個區間時,把所有與它相交的詢問的值$+1$,把所有與它不相交的詢問的值設為$0$。

      在K-D Tree上打標記,最后每個詢問的答案為其值的歷史最大值,時間復雜度$O(n\sqrt{m})$。

      #include<cstdio>
      #include<algorithm>
      const int N=200010,inf=-1,BUF=6000000;
      int n,m,i,id[N],root,cmp_d,X,Y;struct P{int x,y;}a[N];char Buf[BUF],*buf=Buf;
      inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
      struct node{
        int D[2],l,r,Max[2],Min[2];
        int m,d,e,hm,hd,he;
      }t[N];
      inline bool cmp(const node&a,const node&b){return a.D[cmp_d]<b.D[cmp_d];}
      inline void Max(int&a,int b){if(a<b)a=b;}
      inline void Min(int&a,int b){if(a>b)a=b;}
      inline void up(int x){
        id[t[x].e]=x,t[x].e=t[x].he=inf;
        if(t[x].l){
          Max(t[x].Max[0],t[t[x].l].Max[0]);
          Min(t[x].Min[0],t[t[x].l].Min[0]);
          Max(t[x].Max[1],t[t[x].l].Max[1]);
          Min(t[x].Min[1],t[t[x].l].Min[1]);
        }
        if(t[x].r){
          Max(t[x].Max[0],t[t[x].r].Max[0]);
          Min(t[x].Min[0],t[t[x].r].Min[0]);
          Max(t[x].Max[1],t[t[x].r].Max[1]);
          Min(t[x].Min[1],t[t[x].r].Min[1]);
        }
      }
      int build(int l,int r,int D){
        int mid=(l+r)>>1;
        cmp_d=D,std::nth_element(t+l+1,t+mid+1,t+r+1,cmp);
        t[mid].Max[0]=t[mid].Min[0]=t[mid].D[0];
        t[mid].Max[1]=t[mid].Min[1]=t[mid].D[1];
        if(l!=mid)t[mid].l=build(l,mid-1,!D);
        if(r!=mid)t[mid].r=build(mid+1,r,!D);
        return up(mid),mid;
      }
      inline void hdoa(node&x,int v){
        Max(x.hm,x.m+v);
        if(x.e>inf)Max(x.he,x.e+v);else Max(x.hd,x.d+v);
      }
      inline void hdoc(node&x,int v){Max(x.hm,v);Max(x.he,v);}
      inline void doa(node&x,int v){
        Max(x.hm,x.m+=v);
        if(x.e>inf)Max(x.he,x.e+=v);else Max(x.hd,x.d+=v);
      }
      inline void doc(node&x,int v){Max(x.hm,x.m=v);Max(x.he,x.e=v);x.d=0;}
      inline void pb(node&x){
        if(x.hd){
          if(x.l)hdoa(t[x.l],x.hd);
          if(x.r)hdoa(t[x.r],x.hd);x.hd=0;
        }
        if(x.he>inf){
          if(x.l)hdoc(t[x.l],x.he);
          if(x.r)hdoc(t[x.r],x.he);
          x.he=inf;
        }
        if(x.d){
          if(x.l)doa(t[x.l],x.d);
          if(x.r)doa(t[x.r],x.d);
          x.d=0;
        }else if(x.e>inf){
          if(x.l)doc(t[x.l],x.e);
          if(x.r)doc(t[x.r],x.e);
          x.e=inf;
        }
      }
      void change(node&x){
        if(x.Min[0]>X||x.Max[1]<Y){doc(x,0);return;}
        if(x.Max[0]<=X&&x.Min[1]>=Y){doa(x,1);return;}
        pb(x);
        if(x.D[0]<=X&&x.D[1]>=Y)Max(x.hm,++x.m);else x.m=0;
        if(x.l)change(t[x.l]);
        if(x.r)change(t[x.r]);
      }
      void dfs(node&x){
        pb(x);
        if(x.l)dfs(t[x.l]);
        if(x.r)dfs(t[x.r]);
      }
      int main(){
        fread(Buf,1,BUF,stdin),read(n),read(m);
        for(i=1;i<=n;i++)read(a[i].x),read(a[i].y);
        for(i=1;i<=m;i++)read(t[i].D[0]),read(t[i].D[1]),t[i].e=i;
        root=build(1,m,0);
        for(i=1;i<=n;i++)X=a[i].y,Y=a[i].x,change(t[root]);
        dfs(t[root]);
        for(i=1;i<=m;i++)printf("%d\n",t[id[i]].hm);
      }
      

        

      Laser Pool [A]

      與橫線以及豎線的交點個數很容易求,那么只要求出橫線豎線交點與運動軌跡的交點數即可。

      運動軌跡可以劃分成若干條貫穿邊界的斜線,對于第一條和最后一條,可以用bitset暴力統計。

      對于中間的部分,斜線都是完整的,可以FFT預處理。

      時間復雜度$O(n\log n+\frac{nq}{32})$。

      #include<cstdio>
      #include<cmath>
      #include<algorithm>
      using namespace std;
      typedef unsigned int U;
      const int N=100010,M=10010,L=262150;
      int n,m,cb,ce,i,j,ab[N*2],arb[N*2],rab[N*2],rarb[N*2],g[65540];
      char a[N],b[N];
      struct Que{int x,y,vx,vy,t,ans;}e[M];
      inline int popcount(U x){return g[x>>16]+g[x&65535];}
      struct BIT{
        U v[N/32+5];
        void clr(){for(int i=0;i<=cb;i++)v[i]=0;}
        U get(int x){return v[x>>5]>>(x&31)&1;}
        void set(int x,U y){if((v[x>>5]>>(x&31)&1)^y)v[x>>5]^=1U<<(x&31);}
        void shl(int x,int y){
          int A=y>>5,B=y&31,C=(32-B)&31,D=x>>5,E=(D<<5)+31;
          for(int i=x;i<=E;i++)set(i,get(i+y));
          for(int i=D+1;i<=cb;i++){
            v[i]=v[i+A]>>B;
            if(C)v[i]|=v[i+A+1]<<C;
          }
        }
        void copy(int x,int y,const BIT&p){for(int i=x;i<=y;i++)v[i]=p.v[i];}
        void And(int x,int y,const BIT&p){for(int i=x;i<=y;i++)v[i]&=p.v[i];}
        int count(int x,int y){
          int A=x>>5,B=y>>5,C,ret=0;
          if(A==B){
            for(int i=x;i<=y;i++)if(v[A]>>(i&31)&1)ret++;
            return ret;
          }
          for(int i=A+1;i<B;i++)ret+=popcount(v[i]);
          C=(A<<5)+31;
          for(int i=x;i<=C;i++)if(v[A]>>(i&31)&1)ret++;
          C=B<<5;
          for(int i=C;i<=y;i++)if(v[B]>>(i&31)&1)ret++;
          return ret;
        }
      }bA,bB,brA,brB,tA,tB;
      inline void read(int&a){
        char c;bool f=0;a=0;
        while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-')));
        if(c!='-')a=c-'0';else f=1;
        while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';
        if(f)a=-a;
      }
      namespace FFT{
      int k,j,pos[L];
      const double pi=acos(-1.0);
      struct comp{
        double r,i;comp(double _r=0,double _i=0){r=_r,i=_i;}
        comp operator+(const comp&x){return comp(r+x.r,i+x.i);}
        comp operator-(const comp&x){return comp(r-x.r,i-x.i);}
        comp operator*(const comp&x){return comp(r*x.r-i*x.i,r*x.i+i*x.r);}
      }a[L],ra[L],b[L],rb[L],c[L];
      void FFT(comp a[],int n,int t){
        for(int i=1;i<n;i++)if(i<pos[i])swap(a[i],a[pos[i]]);
        for(int d=0;(1<<d)<n;d++){
          int m=1<<d,m2=m<<1;
          double o=pi*2/m2*t;comp _w(cos(o),sin(o));
          for(int i=0;i<n;i+=m2){
            comp w(1,0);
            for(int j=0;j<m;j++){
              comp&A=a[i+j+m],&B=a[i+j],t=w*A;
              A=B-t;B=B+t;w=w*_w;
            }
          }
        }
        if(t==-1)for(int i=0;i<n;i++)a[i].r/=n;
      }
      void work(){
        for(k=1;k<=n||k<=m;k<<=1);k<<=1;
        j=__builtin_ctz(k)-1;
        for(i=0;i<k;i++)pos[i]=pos[i>>1]>>1|((i&1)<<j);
        for(i=1;i<=n;i++)a[i].r=ra[n-i+1].r=::a[i];
        for(i=1;i<=m;i++)b[i].r=rb[m-i+1].r=::b[i];
        FFT(a,k,1),FFT(ra,k,1),FFT(b,k,1),FFT(rb,k,1);
        for(i=0;i<k;i++)c[i]=a[i]*b[i];
        FFT(c,k,-1);
        for(i=1;i<=n+m;i++)ab[i]=(int)(c[i].r+0.5);
        for(i=0;i<k;i++)c[i]=a[i]*rb[i];
        FFT(c,k,-1);
        for(i=1;i<=n+m;i++)arb[i]=(int)(c[i].r+0.5);
        for(i=0;i<k;i++)c[i]=ra[i]*b[i];
        FFT(c,k,-1);
        for(i=1;i<=n+m;i++)rab[i]=(int)(c[i].r+0.5);
        for(i=0;i<k;i++)c[i]=ra[i]*rb[i];
        FFT(c,k,-1);
        for(i=1;i<=n+m;i++)rarb[i]=(int)(c[i].r+0.5);
      }
      }
      namespace Solve{
      bool a[N],b[N];
      int sa[N],sb[N];
      int cnt,idx[4][N],idy[4][N];
      int tot,st[N*8],en[N*8],v[N*8],pos[N*8],cur,q[N*8],sw[N*8];long long sl[N*8];
      struct E{int sx,sy,ex,ey,len,w,d,nxt;}f[N*8];
      inline bool check(int x,int y){return b[x]&&a[y];}
      inline int abs(int x){return x>0?x:-x;}
      inline int&getid(int x,int y,int d){
        if(y==1||y==n)return idx[d][x];
        return idy[d][y];
      }
      inline void makerev(int x){
        f[x].sx=f[x-1].ex;
        f[x].sy=f[x-1].ey;
        f[x].ex=f[x-1].sx;
        f[x].ey=f[x-1].sy;
        f[x].w=f[x-1].w;
        f[x].d=(f[x-1].d+2)&3;
      }
      inline int getnxt(int x,int y,int d){
        if(d==0){
          if(x<m&&y==n)return getid(x,y,(d+1)&3);
          if(y==n)return getid(x,y,(d+2)&3);
          return getid(x,y,(d+3)&3);
        }
        if(d==2){
          if(x>1&&y==1)return getid(x,y,(d+1)&3);
          if(y==1)return getid(x,y,(d+2)&3);
          return getid(x,y,(d+3)&3);
        }
        if(d==1){
          if(x<m&&y==1)return getid(x,y,(d+3)&3);
          if(y==1)return getid(x,y,(d+2)&3);
          return getid(x,y,(d+1)&3);
        }
        if(x>1&&y==n)return getid(x,y,(d+3)&3);
        if(y==n)return getid(x,y,(d+2)&3);
        return getid(x,y,(d+1)&3);
      }
      inline int cal(int x,int t,int n,int*s){
        if(x+t<=n)return s[x+t]-s[x-1];
        t-=n-x;
        int ret=s[n-1]-s[x-1];
        ret+=t/(n+n-2)*(s[n]+s[n-1]-s[1]);
        t%=n+n-2;
        if(t<n)return ret+s[n]-s[n-t-1];
        return ret+s[n]-s[1]+s[t-n+2];
      }
      inline int search(int L,int r,int x){
        int l=L,t=L-1,mid;
        while(l<=r)if(sl[mid=(l+r)>>1]-sl[L-1]<=x)l=(t=mid)+1;else r=mid-1;
        return t;
      }
      inline void ask(int x,int y,int t,int p){
        int&ans=e[p].ans;
        ans=cal(x,t,m,sb)+cal(y,t,n,sa);
        int ex=m,ey=y-x+m;
        if(ey>n)ey=n,ex=x-y+n;
        int d=ex-x;
        if(t<=d){
          tA.copy(y>>5,cb,bA);
          tB.copy(x>>5,cb,bB);
          tB.shl(0,x);
          tA.shl(0,y);
          tA.And(0,t>>5,tB);
          ans-=tA.count(0,t);
          return;
        }
        if(d){
          tA.copy(y>>5,cb,bA);
          tB.copy(x>>5,cb,bB);
          tB.shl(0,x);
          tA.shl(0,y);
          tA.And(0,(d-1)>>5,tB);
          ans-=tA.count(0,d-1);
        }
        t-=d;
        int o=getnxt(ex,ey,0);
        int l=st[v[o]],r=en[v[o]];
        o=pos[o];
        int u=search(o,r,t);
        ans-=sw[u]-sw[o-1];
        t-=sl[u]-sl[o-1];
        o=u+1;
        if(o>r){
          ans-=t/(sl[r]-sl[l-1])*(sw[r]-sw[l-1]);
          t%=sl[r]-sl[l-1];
          u=search(l,r,t);
          ans-=sw[u]-sw[l-1];
          t-=sl[u]-sl[l-1];
          o=u+1;
        }
        o=q[o];
        x=f[o].sx,y=f[o].sy;
        if(f[o].d==0){
          tA.copy(y>>5,cb,bA);
          tB.copy(x>>5,cb,bB);
        }
        if(f[o].d==1){
          y=n-y+1;
          tA.copy(y>>5,cb,brA);
          tB.copy(x>>5,cb,bB);
        }
        if(f[o].d==2){
          x=m-x+1;
          y=n-y+1;
          tA.copy(y>>5,cb,brA);
          tB.copy(x>>5,cb,brB);
        }
        if(f[o].d==3){
          x=m-x+1;
          tA.copy(y>>5,cb,bA);
          tB.copy(x>>5,cb,brB);
        }
        tB.shl(0,x);
        tA.shl(0,y);
        tA.And(0,t>>5,tB);
        ans-=tA.count(0,t);
      }
      void work(int*A,int*B){
        for(i=1;i<=n;i++)sa[i]=sa[i-1]+a[i],bA.set(i,a[i]),brA.set(n-i+1,a[i]);
        for(i=1;i<=m;i++)sb[i]=sb[i-1]+b[i],bB.set(i,b[i]),brB.set(m-i+1,b[i]);
        cnt=0;
        for(i=1;i<m;i++){
          cnt++;
          f[cnt].sx=i,f[cnt].sy=1;
          f[cnt].ex=m,f[cnt].ey=m-i+1;
          if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=n-1+i;
          f[cnt].w=B[m-i+2];
          f[cnt].d=0;
          makerev(++cnt);
        }
        for(i=2;i<n;i++){
          cnt++;
          f[cnt].sx=1,f[cnt].sy=i;
          f[cnt].ex=m,f[cnt].ey=m-1+i;
          if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=n-i+1;
          f[cnt].w=B[m+i];
          f[cnt].d=0;
          makerev(++cnt);
        }
        for(i=2;i<=m;i++){
          cnt++;
          f[cnt].sx=i,f[cnt].sy=1;
          f[cnt].ex=1,f[cnt].ey=i;
          if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=i+1-n;
          f[cnt].w=A[i+1];
          f[cnt].d=3;
          makerev(++cnt);
        }
        for(i=2;i<n;i++){
          cnt++;
          f[cnt].sx=m,f[cnt].sy=i;
          f[cnt].ex=1,f[cnt].ey=m+i-1;
          if(f[cnt].ey>n)f[cnt].ey=n,f[cnt].ex=m+i-n;
          f[cnt].w=A[i+m];
          f[cnt].d=3;
          makerev(++cnt);
        }
        for(i=1;i<=cnt;i++){
          f[i].len=abs(f[i].sx-f[i].ex);
          f[i].w-=check(f[i].ex,f[i].ey);
          getid(f[i].sx,f[i].sy,f[i].d)=i;
        }
        for(i=1;i<=cnt;i++)f[i].nxt=getnxt(f[i].ex,f[i].ey,f[i].d);
        cur=tot=0;
        for(i=1;i<=cnt;i++)v[i]=0;
        for(i=1;i<=cnt;i++)if(!v[i]){
          st[++tot]=cur+1;
          for(j=i;!v[j];j=f[j].nxt)v[q[++cur]=j]=tot;
          en[tot]=cur;
        }
        for(i=1;i<=cnt;i++)sl[i]=sl[i-1]+f[q[i]].len,sw[i]=sw[i-1]+f[q[i]].w,pos[q[i]]=i;
      }
      }
      int main(){
        for(i=1;i<65536;i++)g[i]=g[i>>1]+(i&1);
        read(n),read(m);
        scanf("%s%s",a+1,b+1);
        for(i=1;i<=n;i++)a[i]-='0';
        for(i=1;i<=m;i++)b[i]-='0';
        read(ce);
        for(i=1;i<=ce;i++)read(e[i].x),read(e[i].y),read(e[i].vx),read(e[i].vy),read(e[i].t);
        FFT::work();
        cb=(n>m?n:m)>>5;
        for(i=1;i<=n;i++)Solve::a[i]=a[i];
        for(i=1;i<=m;i++)Solve::b[i]=b[i];
        Solve::work(ab,arb);
        for(i=1;i<=ce;i++)if(e[i].vx==1&&e[i].vy==1)Solve::ask(e[i].x,e[i].y,e[i].t,i);
        for(i=1;i<=n;i++)Solve::a[i]=a[n-i+1];
        for(i=1;i<=m;i++)Solve::b[i]=b[i];
        Solve::work(rab,rarb);
        for(i=1;i<=ce;i++)if(e[i].vx==1&&e[i].vy==-1)Solve::ask(e[i].x,n-e[i].y+1,e[i].t,i);
        for(i=1;i<=n;i++)Solve::a[i]=a[i];
        for(i=1;i<=m;i++)Solve::b[i]=b[m-i+1];
        Solve::work(arb,ab);
        for(i=1;i<=ce;i++)if(e[i].vx==-1&&e[i].vy==1)Solve::ask(m-e[i].x+1,e[i].y,e[i].t,i);
        for(i=1;i<=n;i++)Solve::a[i]=a[n-i+1];
        for(i=1;i<=m;i++)Solve::b[i]=b[m-i+1];
        Solve::work(rarb,rab);
        for(i=1;i<=ce;i++)if(e[i].vx==-1&&e[i].vy==-1)Solve::ask(m-e[i].x+1,n-e[i].y+1,e[i].t,i);
        for(i=1;i<=ce;i++)printf("%d\n",e[i].ans);
      }
      

        

      The Shortest Period [B]

      枚舉答案長度$L$,設$A$和$B$分別為第一個循環節和反串的第一個循環節:

      1. 壞點不在$A$,那么可以暴力匹配檢驗。

      2. 壞點不在$B$,那么把串翻轉后不在$A$中,轉化為$1$。

      3. 壞點在$A$和$B$的交里面,那么只要長度為$N-L+1$的前后綴相同,那么就存在長度為$L$的循環節。

      通過擴展KMP和Hash快速判斷即可,時間復雜度$O(dn\log n)$。

      #include<cstdio>
      const int N=200010,P=233;
      int T,n,i,j,t,k,p,l,ans,g[N];char a[N];unsigned int pow[N],f[N];
      inline void swap(char&a,char&b){char c=a;a=b;b=c;}
      inline unsigned int hash(int l,int r){return f[r]-f[l-1]*pow[r-l+1];}
      inline int min(int a,int b){return a<b?a:b;}
      void solve(){
        for(i=1;i<=n;i++)f[i]=f[i-1]*P+a[i];
        for(g[i=0]=n;i<n-1&&a[i+1]==a[i+2];i++);
        for(g[t=1]=i,k=2;k<n;k++){
          p=t+g[t]-1,l=g[k-t];
          if(k+l>p){
            j=(p-k+1)>0?(p-k+1):0;
            while(k+j<n&&a[k+j+1]==a[j+1])j++;
            g[k]=j,t=k;
          }else g[k]=l;
        }
        for(i=n;i;i--)g[i]=g[i-1];
        for(i=1;i<ans;i++){
          j=g[i+1];
          if(j==n-i||g[i+2]>=n-i+1)ans=i;else{
            j+=i+2,k=(j-2)/i*i+1,t=k+i;
            if(t>n)t=n;
            if(hash(j,t)!=hash(j-k,t-k)||g[t+1]<n-t)continue;
            for(t++;t<=n;t+=i)if(g[t]<min(i,n-t+1))break;
            if(t>n)ans=i;
          }
        }
      }
      int main(){
        for(pow[0]=i=1;i<N;i++)pow[i]=pow[i-1]*P;
        scanf("%d",&T);
        while(T--){
          scanf("%d%s",&n,a+1);
          ans=n-1;
          solve();
          for(i=1;i<n-i+1;i++)swap(a[i],a[n-i+1]);
          solve();
          printf("%d\n",ans);
        }
      }
      

        

      Trial Finals:

      Wyznaczanie planu sieci drogowej 2

      前$n-2$次每次取出一個度數$=1$的點和一個度數$>1$的點連邊;最后一次取出兩個度數$=1$的點連邊。

      #include<cstdio>
      #include<cstdlib>
      const int N=2000005;
      int n,i,x,y,ca,cb,a[N],b[N],f[N],d[N],deg[N];
      void NIE(){
        puts("BRAK");
        std::exit(0);
      }
      int main(){
        scanf("%d",&n);
        for(i=1;i<=n;i++){
          scanf("%d",&deg[i]);
          if(deg[i]==1)a[++ca]=i;else b[++cb]=i;
        }
        for(i=1;i<n-1;i++){
          if(!ca)NIE();
          if(!cb)NIE();
          x=a[ca--];
          y=b[cb--];
          f[x]=y;
          d[x]++;
          d[y]++;
          if(d[y]+1<deg[y])b[++cb]=y;else a[++ca]=y;
        }
        if(!ca)NIE();
        x=a[ca--];
        if(!ca)NIE();
        y=a[ca--];
        f[x]=y;
        d[x]++;
        d[y]++;
        for(i=1;i<=n;i++)if(d[i]!=deg[i])NIE();
        for(i=1;i<=n;i++)if(f[i])printf("%d %d\n",i,f[i]);
      }
      

        

      Finals:

      Computational Biology

      對于每個長度為$m$的子串,由其向循環移一位的字符串hash連邊,找最大環即可。

      時間復雜度$O(qn\log n)$。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      typedef unsigned long long ull;
      typedef pair<ull,ull>P;
      const int N=500005,S=233;
      int n,q,m,ce,i,j,f[N],vis[N],ans,now;
      char a[N];
      ull p[N],tmp,base;
      P e[N];
      int main(){
        scanf("%d%d%s",&n,&q,a+1);
        for(p[0]=i=1;i<=n;i++)p[i]=p[i-1]*S;
        while(q--){
          scanf("%d",&m);
          tmp=ce=0,base=p[m];
          for(i=1;i<=n;i++){
            tmp=tmp*S+a[i];
            if(i>m)tmp-=base*a[i-m];
            e[++ce]=P(tmp,tmp*S-(base-1)*a[i-m+1]);
          }
          sort(e+1,e+ce+1);
          ans=0;
          for(i=1;i<=ce;i++)f[i]=0;
          for(i=1;i<=ce;i=j){
            for(j=i;j<=ce&&e[i]==e[j];j++);
            f[i]=j-i;
          }
          for(i=1;i<=ce;i++)if(f[i]){
            tmp=e[i].second;
            now=0;
            while(1){
              j=lower_bound(e+1,e+ce+1,P(tmp,0))-e;
              if(j<1||j>ce||e[j].first!=tmp||!f[j])break;
              now+=f[j];
              f[j]=0;
              if(j==i){
                if(now>ans)ans=now;
                break;
              }
              tmp=e[j].second;
            }
          }
          printf("%d\n",ans);
        }
      }
      

        

      Byteland Worldbeat Publishers

      不妨設$n=m$,考慮一個完美匹配:

      • 對于每條匹配邊$(左u,右v,w)$,連邊$左 u\rightarrow 右 v$,邊權$w$。
      • 對于每條非匹配邊$(左u,右v,w)$,連邊$右 v\rightarrow 左 u$,邊權$-w$。

      那么每個完美匹配權值和相同當且僅當每個環的邊權和都是$0$。

      注意到所有環都可以由$左u\rightarrow 右 v\rightarrow 左 u+1\rightarrow 右 v+1\rightarrow 左 u$拼成,于是對于所有$(u,v)$檢查這樣的環邊權和是否是$0$即可。

      將信息排序后雙指針即可完成檢查。

      時間復雜度$O(k\log k+n+m)$。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      const int N=100005,M=300005;
      int Case,n,m,i,j,k,o,nxt,A,B,C,D,st[N],en[N];
      struct E{int x,l,r,v;}e[M];
      inline bool cmp(const E&a,const E&b){return a.x==b.x?a.l<b.l:a.x<b.x;}
      inline void up(int x){
        if(x<o||x>nxt)return;
        nxt=x;
      }
      bool check(){
        scanf("%d%d",&n,&m);
        if(n<m)n=m;
        scanf("%d",&m);
        for(i=1;i<=m;i++)scanf("%d%d%d%d",&e[i].x,&e[i].l,&e[i].r,&e[i].v);
        sort(e+1,e+m+1,cmp);
        for(i=1;i<=n;i++)st[i]=m+1,en[i]=0;
        for(i=1;i<=m;i++)en[e[i].x]=i;
        for(i=m;i;i--)st[e[i].x]=i;
        for(i=1;i<n;i++){
          j=st[i],k=st[i+1],o=1;
          while(o<n){
            while(j<=en[i]&&e[j].r<o)j++;
            while(k<=en[i+1]&&e[k].r<o)k++;
            A=0;
            if(j<=en[i]&&e[j].l<=o)A=e[j].v;
            B=0;
            if(k<=en[i+1]&&e[k].l<=o)B=e[k].v;
            o++;
            while(j<=en[i]&&e[j].r<o)j++;
            while(k<=en[i+1]&&e[k].r<o)k++;
            C=0;
            if(j<=en[i]&&e[j].l<=o)C=e[j].v;
            D=0;
            if(k<=en[i+1]&&e[k].l<=o)D=e[k].v;
            if(A+D!=B+C)return 0;
            nxt=n;
            up(n-1);
            if(j<=en[i]){
              up(e[j].l-2);
              up(e[j].l-1);
              up(e[j].r-1);
              up(e[j].r);
            }
            if(k<=en[i+1]){
              up(e[k].l-2);
              up(e[k].l-1);
              up(e[k].r-1);
              up(e[k].r);
            }
            o=nxt;
          }
        }
        return 1;
      }
      int main(){
        scanf("%d",&Case);
        while(Case--)puts(check()?"TAK":"NIE");
      }
      

        

      Exam

      即求出與每個矩形有交的編號最大的矩形$f[i]$,若$f[i]\leq i$則矩形$i$處于頂層。

      枚舉矩形$i$和矩形$j$的形狀,那么詢問范圍是二維滑窗,對著$x$掃描線,對著$y$維護線段樹即可。

      時間復雜度$O(n\log n)$。

      #include<cstdio>
      #include<algorithm>
      using namespace std;
      const int N=100010,M=262150;
      int n,m,A,B,i,j,k,tmp,q[N],id[N],pos[N],v[M],f[N],ans,fin[N];
      struct E{int x,y,r,t;}e[N];
      inline bool cmpe(const E&a,const E&b){return a.x<b.x;}
      inline bool cmp(int x,int y){return e[x].y<e[y].y;}
      void build(int x,int a,int b){
        v[x]=0;
        if(a==b){pos[a]=x;return;}
        int mid=(a+b)>>1;
        build(x<<1,a,mid),build(x<<1|1,mid+1,b);
      }
      inline void change(int x,int p){
        v[x=pos[x]]=p;
        for(x>>=1;x;x>>=1)v[x]=max(v[x<<1],v[x<<1|1]);
      }
      inline void up(int&a,int b){a<b?(a=b):0;}
      void ask(int x,int a,int b,int c,int d){
        if(e[q[a]].y>=d||e[q[b]].y<=c||!v[x])return;
        if(e[q[a]].y>c&&e[q[b]].y<d){up(tmp,v[x]);return;}
        if(a==b)return;
        int mid=(a+b)>>1;
        ask(x<<1,a,mid,c,d);
        ask(x<<1|1,mid+1,b,c,d);
      }
      void gao(int me,int him,int xl,int xr,int yl,int yr){
        for(m=0,i=1;i<=n;i++)if(e[i].r==him)q[++m]=i;
        if(!m)return;
        sort(q+1,q+m+1,cmp);
        for(i=1;i<=m;i++)id[q[i]]=i;
        build(1,1,m);
        for(i=j=k=1;i<=n;i++)if(e[i].r==me){
          while(j<=n&&e[j].x<e[i].x+xr){
            if(e[j].r==him)change(id[j],e[j].t);
            j++;
          }
          while(k<=n&&e[k].x<=e[i].x+xl){
            if(e[k].r==him)change(id[k],0);
            k++;
          }
          tmp=0;
          ask(1,1,m,e[i].y+yl,e[i].y+yr);
          up(f[e[i].t],tmp);
        }
      }
      int main(){
        scanf("%d%d%d",&n,&A,&B);
        for(i=1;i<=n;i++)scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].r),e[i].t=i;
        sort(e+1,e+n+1,cmpe);
        gao(0,0,-B,B,-A,A);
        gao(1,1,-A,A,-B,B);
        gao(0,1,-A,B,-B,A);
        gao(1,0,-B,A,-A,B);
        for(i=1;i<=n;i++)if(f[i]<=i)fin[++ans]=i;
        printf("%d\n",ans);
        for(i=1;i<=ans;i++)printf("%d ",fin[i]);
      }
      

        

      Computational Geometry

      $n$為奇數則無解,否則$n$的方案可以由$n-2$的方案右邊拼上$1\times 2$或$2\times 1$的矩形得到。

      #include<cstdio>
      int n,i,o,x;
      int main(){
        scanf("%d",&n);
        if(n&1)return puts("NIE"),0;
        puts("0 0");
        puts("0 2");
        puts("2 2");
        for(i=4,x=2;i<n;i+=2,o^=1){
          if(!o){
            printf("%d 1\n",x);
            printf("%d 1\n",x+=2);
          }else{
            printf("%d 2\n",x);
            printf("%d 2\n",x+=1);
          }
        }
        printf("%d 0",x);
      }
      

        

      Coprime Numbers

      設$g_i$表示數字$i$倍數的出現次數,$f_i$表示有多少對數字的最大公約數是$i$的倍數,則$f_i=C(g_i,2)-f_{2i}-f_{3i}-\dots$。

      時間復雜度$O(a\log a)$。

      #include<cstdio>
      const int M=3000005;
      int n,m,i,j,x,c[M];long long f[M];
      int main(){
        scanf("%d",&n);
        while(n--){
          scanf("%d",&x);
          c[x]++;
          if(x>m)m=x;
        }
        for(i=m;i;i--){
          for(j=i;j<=m;j+=i)f[i]+=c[j];
          f[i]=1LL*f[i]*(f[i]-1);
          for(j=i+i;j<=m;j+=i)f[i]-=f[j];
        }
        printf("%lld",f[1]/2);
      }
      

        

      Prime prime power

      對于$a^b$,如果$b=2$,那么在$[\sqrt{n},\sqrt{n}+k\log k]$內必定能找到$k$個質數作為$a$。

      篩出$n^{\frac{1}{4}}$內的所有質數,暴力枚舉所有落在該區間內的倍數,將其篩掉,即可判斷每個數是否是質數。

      然后以最大的質數的平方作為上界,枚舉更大的$a$和$b$,這里方案數指數級下降,故暴力即可。

      最后排序輸出第$k$小的值即可。

      時間復雜度$O(n^{\frac{1}{3}}+k\log^2k)$。

      #include<cstdio>
      #include<algorithm>
      #include<cmath>
      using namespace std;
      typedef long long ll;
      const int N=1050010;
      ll n,lim,t,o,b[66],q[N*2];int cnt,k,m,i,j,a[66],p[N],tot;bool v[N],vis[N*2];
      inline ll pow(ll a,int b){
        ll t=1;
        while(b--){
          if(a>lim/t)return lim+1;
          t*=a;
        }
        return t;
      }
      inline ll powfast(ll a,int b){ll t=1;for(;b;b>>=1,a*=a)if(b&1)t*=a;return t;}
      void sieve(ll n){
        int i,j;
        for(tot=0,i=2;i<=n;i++){
          if(!v[i])p[tot++]=i;
          for(j=0;j<tot&&i*p[j]<=n;j++){
            v[i*p[j]]=1;
            if(i%p[j]==0)break;
          }
        }
      }
      inline void check(int x){for(ll i=max(t/x*x,2LL*x);i<=lim;i+=x)if(i>=t)vis[i-t]=1;}
      int main(){
        scanf("%lld%d",&n,&k);
        t=max((ll)sqrt(n)-10,2LL);
        while(t*t<=n)t++;
        sieve((ll)sqrt(lim=t+max(k,10)*21)+5);
        for(i=0;i<tot;i++)check(p[i]);
        for(o=t;o<=lim&&cnt<k;o++)if(!vis[o-t])q[++cnt]=o*o;
        lim=q[cnt];
        for(i=3;;a[++m]=i++)if((1LL<<i)>lim)break;
        for(b[1]=2;(b[1]+1)*(b[1]+1)*(b[1]+1)<=lim;b[1]++);
        for(i=2;i<=m;i++)for(b[i]=b[i-1];pow(b[i],a[i])>lim;b[i]--);
        sieve(max(b[1],1LL*a[m]));
        for(i=1;i<=m;i++)if(!v[a[i]]){
          for(j=0;j<tot&&powfast(p[j],a[i])<=n;j++);
          for(;j<tot&&p[j]<=b[i];j++)q[++cnt]=powfast(p[j],a[i]);
        }
        sort(q+1,q+cnt+1);
        printf("%lld",q[k]);
      }
      

        

      Hard Choice

      在每條邊兩個點中間加上一個虛擬點代表這條邊權,就可以化邊權為點權。

      把沒刪掉的邊用LCT維護一棵生成樹,樹邊都是橋。

      對于一條非樹邊,把樹上對應路徑上所有邊的權值都修改為$0$,表示都不是橋。

      然后倒著處理詢問,對于每次刪掉的邊,把兩點路徑上邊權都修改為$0$。

      詢問等價于查詢兩點間邊權和,若兩點連通且路徑上不存在橋,則有解。

      #include<cstdio>
      #include<map>
      const int N=200010,BUF=5000000;
      char Buf[BUF],*buf=Buf;
      int a[N],n,m,i,x,fa[N],edge[N][2],ask[N][4],q;
      struct LCT{int f,son[2],sum,data;bool rev,tag;}T[N];
      int father(int x){return fa[x]==x?x:fa[x]=father(fa[x]);}
      std::map<int,bool>del[N>>1];
      inline void swap(int&a,int&b){int c=a;a=b;b=c;}
      inline bool isroot(int x){return !T[x].f||T[T[x].f].son[0]!=x&&T[T[x].f].son[1]!=x;}
      inline void rev1(int x){if(!x)return;swap(T[x].son[0],T[x].son[1]),T[x].rev^=1;}
      inline void makezero1(int x){if(!x)return;T[x].sum=T[x].data=0;T[x].tag=1;}
      inline void pb(int x){
        if(T[x].rev)rev1(T[x].son[0]),rev1(T[x].son[1]),T[x].rev=0;
        if(T[x].tag)makezero1(T[x].son[0]),makezero1(T[x].son[1]),T[x].tag=0;
      }
      inline void up(int x){T[x].sum=T[x].data|T[T[x].son[0]].sum|T[T[x].son[1]].sum;}
      inline void rotate(int x){
        int y=T[x].f,w=T[y].son[1]==x;
        T[y].son[w]=T[x].son[w^1];
        if(T[x].son[w^1])T[T[x].son[w^1]].f=y;
        if(T[y].f){
          int z=T[y].f;
          if(T[z].son[0]==y)T[z].son[0]=x;else if(T[z].son[1]==y)T[z].son[1]=x;
        }
        T[x].f=T[y].f;T[x].son[w^1]=y;T[y].f=x;up(y);
      }
      inline void splay(int x){
        int s=1,i=x,y;a[1]=i;
        while(!isroot(i))a[++s]=i=T[i].f;
        while(s)pb(a[s--]);
        while(!isroot(x)){
          y=T[x].f;
          if(!isroot(y)){if((T[T[y].f].son[0]==y)^(T[y].son[0]==x))rotate(x);else rotate(y);}
          rotate(x);
        }
        up(x);
      }
      inline void access(int x){for(int y=0;x;y=x,x=T[x].f)splay(x),T[x].son[1]=y,up(x);}
      inline void makeroot(int x){access(x);splay(x);rev1(x);}
      inline void link(int x,int y){makeroot(x);T[x].f=y;access(x);}
      inline void makezero(int x,int y){
        if(father(x)!=father(y)){
          fa[father(x)]=father(y);
          n++;
          T[n].sum=T[n].data=1;
          link(x,n);link(n,y);
          return;
        }
        makeroot(x);
        access(y);
        splay(x);
        makezero1(x);
      }
      inline int getsum(int x,int y){
        if(father(x)!=father(y))return 1;
        makeroot(x);
        access(y);
        splay(x);
        return T[x].sum;
      }
      inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
      int main(){
        fread(Buf,1,BUF,stdin);read(n);read(m);read(q);
        for(i=1;i<=n;i++)fa[i]=i;
        for(i=1;i<=m;i++){
          read(edge[i][0]);read(edge[i][1]);
          if(edge[i][0]>edge[i][1])swap(edge[i][0],edge[i][1]);
        }
        for(i=1;i<=q;i++){
          while(*buf!='Z'&&*buf!='P')buf++;
          ask[i][0]=x=*buf=='P',buf++;
          read(ask[i][1]);read(ask[i][2]);
          if(ask[i][1]>ask[i][2])swap(ask[i][1],ask[i][2]);
          if(!x)del[ask[i][1]][ask[i][2]]=1;
        }
        for(i=1;i<=m;i++)if(!del[edge[i][0]][edge[i][1]])if(father(edge[i][0])!=father(edge[i][1])){
          fa[father(edge[i][0])]=father(edge[i][1]);
          n++;
          T[n].sum=T[n].data=1;
          link(edge[i][0],n);link(n,edge[i][1]);
          del[edge[i][0]][edge[i][1]]=1;
        }
        for(i=1;i<=m;i++)if(!del[edge[i][0]][edge[i][1]])makezero(edge[i][0],edge[i][1]);
        for(i=q;i;i--)if(!ask[i][0])makezero(ask[i][1],ask[i][2]);else ask[i][3]=getsum(ask[i][1],ask[i][2]);
        for(i=1;i<=q;i++)if(ask[i][0])puts(ask[i][3]?"NIE":"TAK");
      }
      

        

      posted @ 2022-10-16 17:26  Claris  閱讀(189)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲a毛片| 国产仑乱无码内谢| 四虎永久在线高清免费看| 精品日韩人妻中文字幕| 国产精品成人一区二区不卡| 亚洲天堂一区二区三区四区| 欧美成人精品三级在线观看| 精品黄色av一区二区三区| 欧美成人精品三级网站视频| 国产亚洲精品成人av久| 亚洲欧美精品在线| 久久精品国产99国产精品澳门| 台中县| 国产中文字幕精品喷潮| 久热这里只有精品12| 国产精品视频中文字幕| 久久精品99国产国产精| 精品一区二区三区少妇蜜臀| 亚洲精品麻豆一区二区| 中国极品少妇xxxxx| 亚洲乱码一二三四区国产| 中文字幕无线码在线观看| 四虎在线成人免费观看| 国产成人亚洲日韩欧美| 久久精品国产亚洲av麻豆长发| 日韩伦理片| 国产精品毛片一区视频播| 亚洲一区二区三区日本久久 | 国产盗摄xxxx视频xxxx| 国产日韩一区二区四季| 亚洲国产色婷婷久久99精品91| 精品一区二区三区在线成人 | 亚洲第一区二区快射影院| 国产老熟女视频一区二区| 精品国产乱码久久久久夜深人妻 | 高清精品一区二区三区| 婷婷四虎东京热无码群交双飞视频| 色综合人人超人人超级国碰| 日韩在线视频线观看一区| 少妇人妻互换不带套| 国产精品国产三级国产an|