• 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(添加时记得备注)
  • 相关阅读:
    LINUX创建文件和目录的默认权限
    Fiddler工具使用介绍一
    Jmeter使用指南
    LINUX中如何查看某个端口是否被占用
    Linux下重要日志文件及查看方式
    Linux如何查看文件的创建、修改时间?
    Linux 系统日志和系统信息常用命令介绍
    linux查看系统的日志的一些实用操作
    Linux下查看/管理当前登录用户及用户操作历史记录
    4*4(齐次)矩阵
  • 原文地址:https://www.cnblogs.com/bluefly-hrbust/p/10957637.html
Copyright © 2020-2023  润新知