zoukankan      html  css  js  c++  java
  • 5.30日训练赛

    A. Cthulhu

    问是否有且仅有一个环,并且环的大小>=3个,要求图联通

    直接DFS,如果存在一个环,那么重复访问的节点数目一定是2,首先考虑是链,那么DFS会到链的两个端点,那么由于这是一个环,两个端点会被另外一个端点访问,所以次数是2,最后

    判断图是否联通即可。

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<vector>
    using namespace std;
    vector<int>G[1005];
    int vis[105];
    int cnt;
    void dfs(int x,int fa){
        if (vis[x]!=0){
            vis[x]++;
           // cout<<"--"<<x<<endl;
            cnt++;
            return;
        }else {
            vis[x]=1;
        }
        for (int i=0;i<G[x].size();i++){
            if (G[x][i]!=fa)dfs(G[x][i],x);
        }
    }
    int main(){
      int n,m;
      while(~scanf("%d%d",&n,&m)){
          for (int i=1;i<=n;i++){
            G[i].clear();
          }
          cnt=0;
          int u,v;
          memset(vis,0,sizeof(vis));
          for (int i=1;i<=m;i++){
              scanf("%d%d",&u,&v);
              G[u].push_back(v);
              G[v].push_back(u);
          }
          dfs(1,-1);
          int flag=0;
          for (int i=1;i<=n;i++){
             if (vis[i]==0){
                 flag=1;
             }
          }
          if (flag==0 && cnt==2){
            printf("FHTAGN!
    ");
          }else {
            printf("NO
    ");
          }
      }
      return 0;
    }
    View Code

    B. Increasing by Modulo

    给一串序列,每次操作可以给序列中任意多个数+1,并把这些数%M,问最少操作使得序列非递减。

    二分最大操作,那么每个点的操作一定是小于或等于这个数,贪心的把前面的数尽量置成小的,维护一个前一个的最小状态,最后判断最大操作是否可行。从而判断得到二分上下界,得到最小答案

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    const int maxx = 300006;
    int a[maxx];
    int n,m;
    bool judge(int x){
       int last=a[1];
       if (a[1]+x>=m)last=0;
       for (int i=2;i<=n;i++){
          int tmp=-1;
          if (a[i]>=last){
            tmp=a[i];
              if (a[i]+x>=m && (a[i]+x)%m>=last){
                  tmp=last;
              }
          }else if (a[i]+x>=last){
               tmp=last;
          }
          last=tmp;
          if (tmp==-1)return 0;
       }
      return 1;
    }
    int main(){
       scanf("%d%d",&n,&m);
       for (int i=1;i<=n;i++){
          scanf("%d",&a[i]);
       }
       int l=0,r=m;
       int ans;
       while(l<=r){
          int mid=(l+r)/2;
          if (judge(mid)){
            ans=mid;
            r=mid-1;
          }else {
            l=mid+1;
          }
       }
       printf("%d
    ",ans);
      return 0;
    }
    View Code

    C. Tavas and Malekas

    神仙题。。。给出一个模板串,以前原串长度,以前在原串中的和模板串匹配的多个首位置,问原串有多少种可能。

    肯定是每次枚举原串首位置,外后更新,判断即可。但是很显然直接T飞。。。

    首先如果原串两个相邻位置a[i]-a[i-1]>=len那么,a[i-1]不会影响a[i]随便放

    如果a[i-1]-a[i-1]<len,那么我们考虑,模板串从剩下位置是从a[i]+len-a[i-1]位置和模板串的第一个位置开始匹配。。。如何快速判断这些位置是否匹配呢???

    考虑Next数组,我们求出NEXT数组后,找失配位置,第一失配位置肯定是Len位置,每次把r指针置为Next[r],失配位置一定是r位置,打上标记,就能快速判断是否匹配。

    最后数出没有标记的位置,就是可以随便放置的位置

    /*
    */
    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define LL long long
    using namespace std;
    const int maxx = 1e6+7,MOD = 1e9+7;
    char p[maxx];
    int Next[maxx],a[maxx],n,m,vis1[maxx],vis[maxx];
    LL qpow(LL a,LL b){
      LL sum=1;
      while(b){
         if(b&1)sum=sum*a%MOD;
         a=a*a%MOD;
         b/=2;
      }
      return sum;
    }
    void get_next(){
      memset(vis1,0,sizeof(vis1));
      Next[0]=-1;
      int k=-1,i=0;
      int len=strlen(p);
      while(i<len){
        if (k==-1 || p[i]==p[k]){
            i++;
            k++;
            Next[i]=k;
        }else
          k=Next[k];
      }
      int r=len;
      while(r!=-1){
         vis1[r]=1;
         r=Next[r];
      }
    }
    int main(){
      scanf("%d%d",&n,&m);
      scanf("%s",&p);
    
      for (int i=1;i<=m;i++){
        scanf("%d",&a[i]);
      }
      get_next();
      sort(a+1,a+1+m);
      int len=strlen(p);
      for (int i=1;i<=m;i++){
        if (i==1 || a[i]-a[i-1]>=len){
            for (int j=a[i];j<=a[i]+len-1;j++){
                vis[j]=1;
            }
        }else if (vis1[a[i-1]+len-a[i]]){
            for (int j=a[i-1]+len;j<=a[i]+len-1;j++){
                vis[j]=1;
            }
       }else {
          printf("0
    ");
          return 0;
        }
      }
      LL ans;
      int cnt=0;
      for (int i=1;i<=n;i++){
        if (vis[i]==0){
            cnt++;
        }
      }
      ans=qpow((LL)26,cnt);
      printf("%lld
    ",ans);
      return 0;
    }
    View Code

    D. Fight Against Traffic

    给出N个点,M条路,点i到点j的长度定义为i走个j经过的最小路径数目,给出起点和终点,在一些没有直接路径连接的点连接一条边,有多少对这样增加的路径,不影响i->j的路径长度

    这题还是非常秀的。。。我们可以用BFS跑出从起点到每个点的距离,每个点到终点的距离,那么从起点到i的距离+终点到j的距离+1>=起点到终点的距离,起点到j+终点到i的距离+1>=起点到终点的距离,那对答案就是没有影响的。

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    const int maxx = 1005;
    vector<int>G[maxx];
    int n,m;
    bool vis[maxx];
    int dis_s[maxx];
    int dis_t[maxx];
    int link[maxx][maxx];
    void bfs(int dis[],int s){
       queue<int>q;
       memset(vis,0,sizeof(vis));
       vis[s]=1;
       q.push(s);
       dis[s]=0;
       while(q.size()){
          int x=q.front();
          q.pop();
          for (int i=0;i<G[x].size();i++){
            int nx=G[x][i];
            if (!vis[nx]){
                q.push(nx);
                vis[nx]=1;
                dis[nx]=dis[x]+1;
            }
          }
       }
    }
    int main(){
      int u,v,s,t;
      scanf("%d%d%d%d",&n,&m,&s,&t);
      while(m--){
         scanf("%d%d",&u,&v);
         G[u].push_back(v);
         G[v].push_back(u);
         link[u][v]=1;
         link[v][u]=1;
      }
      bfs(dis_s,s);
      bfs(dis_t,t);
      int cnt=0;
      for (int i=1;i<=n;i++){
        for (int j=i+1;j<=n;j++){
            if (!link[i][j] && dis_s[i]+1+dis_t[j]>=dis_s[t] && dis_t[i]+1+dis_s[j]>=dis_s[t]){
                cnt++;
            }
        }
      }
      printf("%d
    ",cnt);
      return 0;
    }
    View Code

    E.询问有多少对i,j满足a[i]<=y<=a[j],并且y%x==0中y个数是K的对数

    其实就是一个式子a[j]/x-(a[i]-1)/x==k的个数

    我们把a[i]排序,这不影响结果(自己脑补)。那么对于位置i,二分一个上下界满足这个式子的即可。。。

    注意对于i位置的a[i],左边界应该是和a[i]相等的数的最小位置(因为有可能相等。。。)

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<map>
    #define LL long long
    using namespace std;
    const int maxx = 1e5+6;
    int n;
    LL x,k;
    LL a[maxx];
    LL b[maxx];
    map<int,int>p1;
    int main(){
      while(~scanf("%d%lld%lld",&n,&x,&k)){
         p1.clear();
         for (int i=1;i<=n;i++){
             scanf("%lld",&a[i]);
         }
         sort(a+1,a+1+n);
         for (int i=1;i<=n;i++){
            if (a[i]!=a[i-1]){
                p1[a[i]]=i;
            }
         }
         LL ans=0;
         for (int i=1;i<=n;i++){
             int l=p1[a[i]],r=n;
             int low=n+1,up=-1;
             while(l<=r){
                  int mid=(l+r)/2;
                  if((a[mid]/x-(a[i]-1)/x)==k){
                    up=max(up,mid);
                  }
                  if((a[mid]/x-(a[i]-1)/x)>k){
                       r=mid-1;
                  }else {
                       l=mid+1;
                  }
             }
             l=p1[a[i]],r=n;
             while(l<=r){
                 int mid=(l+r)/2;
                 if((a[mid]/x-(a[i]-1)/x)==k){
                    low=min(low,mid);
                  }
                 if((a[mid]/x-(a[i]-1)/x)>=k){
                     r=mid-1;
                 }else {
                     l=mid+1;
                 }
             }
             if (up==-1 || low==n+1){
                continue;
             }
           //  cout<<up<<" "<<low<<endl;
             ans+=(up-low+1);
         }
        printf("%lld
    ",ans);
      }
      return 0;
    }
    View Code

     F. Minimal string

    字符串是坑啊。。。

    给A一个字符串,你有两种操作,一种是把A字符串的最开始的放到字符串B的最后面,

    把字符串B的最后面的字符放到字符串C的最后面

    要求C的字典序最小,A,B到最后全为空,问C是多少?

    写一个更新数组,从后往前遍历,意义为从i位置往后,最小的字典序的字母。

    比较位置i的s[i]和更新数组,如果更新数组更优,把s[i]放到栈里面去,往后继续,否则把栈的比更新数组更优的字符放到字符串C中,然后继续往后找。直到最后

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #include<stack>
    using namespace std;
    stack<char>sta;
    char s[100005];
    char best[100005];
    int main(){
       while(~scanf("%s",s)){
         int len=strlen(s);
         best[len-1]=s[len-1];
         for (int i=len-2;i>=0;i--){
            best[i]=min(best[i+1],s[i]);
         }
         string ans;
         for (int i=0;i<len;i++){
             if (sta.size()==0){
                sta.push(s[i]);
             }else {
    
                while(sta.size() && sta.top()<=best[i]){
                    ans+=sta.top();
                    sta.pop();
                }
                sta.push(s[i]);
             }
         }
         while(sta.size()){
            ans+=sta.top();
            sta.pop();
         }
         cout<<ans<<endl;
    
       }
      return 0;
    }
    View Code

    就做出A-E,貌似好丢脸。。。

    有不懂欢迎咨询 QQ:1326487164(添加时记得备注)
  • 相关阅读:
    Entity SQL 初入
    ObjectQuery查询及方法
    Entity Framework 的事务 DbTransaction
    Construct Binary Tree from Preorder and Inorder Traversal
    Reverse Linked List
    Best Time to Buy and Sell Stock
    Remove Duplicates from Sorted Array II
    Reverse Integer
    Implement Stack using Queues
    C++中const限定符的应用
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10957637.html
Copyright © 2011-2022 走看看