zoukankan      html  css  js  c++  java
  • VK Cup 2017

    传送门

    A. Bear and Friendship Condition(思维or完全图判定)

    •题意

    给你n个人,m个朋友关系

    朋友是会传递的,若A B是朋友,A C是朋友,则必须有B C的朋友关系

    符合这个关系输出YES,否则输出NO

    •思路

    n个人,但凡是有朋友关系的,必定在同一个朋友圈内

    所以可以分成若干个朋友圈

    在一个朋友圈内部,若符合条件肯定是互为朋友

    也就是 是一个完全图

    接下来就是判断是否是完全图了

    举个栗子:1234在一个朋友圈内,且符合条件

    则人与朋友的对应关系为

    1与1 2 3 4为朋友

    2与1 2 3 4为朋友

    3与1 2 3 4为朋友

    4与1 2 3 4为朋友

    即,他们的朋友是完全相同的!

    挨个去判断朋友是否相同显然时间复杂度不够优雅

    只需要排序后,看第一个朋友是否相等就可以

    O(n)变O(1)!

    为什么呢? 因为每个人的朋友圈都要去查看一遍,如果A的朋友圈没有B,但是B的朋友圈有A

    那么,B和A的朋友圈肯定对不上,所以就输出NO了

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn=2e5+5;
     5 vector<int> a[maxn];
     6 //我加vis数组是为了减少不必要的查看来减少时间
     7 //氮素 貌似效率还不如不加vis的,搞不懂 ???
     8 bool vis[maxn];
     9 
    10 int main()
    11 {
    12 //    freopen("C:\Users\14685\Desktop\C++workspace\in&out\contest","r",stdin);
    13     int n,m;
    14     cin>>n>>m;
    15     for(int i=1;i<=m;i++)
    16     {
    17         int x,y;
    18         cin>>x>>y;
    19         a[x].push_back(y);
    20         a[y].push_back(x);
    21     }
    22     ///把自己也加进自己的朋友圈
    23     for(int i=1;i<=n;i++)
    24         a[i].push_back(i);
    25     ///排序
    26     for(int i=1;i<=n;i++)
    27         sort(a[i].begin(),a[i].end());
    28 
    29     ///查看每个人的朋友圈
    30     for(int i=1;i<=n;i++)
    31     {
    32         if(vis[i])
    33             continue;
    34         ///自己的朋友圈和朋友的朋友圈对比
    35         for(int j=0;j<a[i].size();j++)
    36         {
    37             if(a[i].size()==a[a[i][j]].size())
    38             {
    39                 vis[a[i][j]]=true;
    40                 ///朋友圈不相同
    41                 if(a[i][0]!=a[a[i][j]][0])
    42                 {
    43                     puts("NO");
    44                     return 0;
    45                 }
    46             }
    47             else
    48             {
    49                  puts("NO");
    50                  return 0;
    51             }
    52         }
    53     }
    54     puts("YES");
    55 }
    View Code

    B - Bear and Different Names(模拟)

    •题意

    有n个人,从1个人开始每k个一组

    [1,k] [2,k+1]....

    如果有重名的则NO,否则YES

    根据NO和YES的结果输出名字

    名字首字母大写,且1<=名字长度<=10

    •思路

    因为名字长度有限制,可能有很多人名字不同

    所以首先预处理出不同名字来,注意计算名字个数

    (这里踩了坑)

    首先找到第一个YES为切入点,后边的名字可以由他得到

    已经确定了的名字不能再更改!否则会引起与前面的YES/NO不符 (这里也踩了坑

    如果是YES的话就选择新名字,否则选择和这k个人的第一个人相同的名字(也就是首尾名字重合

    然后再找第一个YES前面的人,从第一个YES开始倒找,让他前面的都和他重名

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define ll long long
     4 const int maxn=2e5+5;
     5 string name[55],nname[3000];
     6 string s[55];
     7 int wh[10];
     8 ///预处理名字
     9 void Init()
    10 {
    11     for(int i=0;i < 10;++i)
    12         wh[i]=i;
    13     int cnt=0;
    14     do
    15     {
    16         for(int i=0;i<10;i++)
    17         {
    18             if(i==0)
    19                 nname[++cnt]=wh[0]+'A';
    20             else
    21                 nname[cnt]+=(wh[i]+'a');
    22         }
    23         if(cnt>2500)
    24             return ;
    25     }while(next_permutation(wh,wh+10));
    26 }
    27 int main()
    28 {
    29 //    freopen("C:\Users\14685\Desktop\C++workspace\in&out\contest","r",stdin);
    30     int n,m;
    31     cin>>n>>m;
    32     bool flag=false;
    33     Init();
    34     int cut=0;
    35     for(int i=1;i<=n-m+1;i++)
    36     {
    37         cin>>s[i];
    38         if(s[i]=="YES")
    39         {
    40             flag=true;
    41             for(int j=i;j<=i+m-1;j++)
    42                 if(name[j].empty())
    43                     name[j]=nname[++cut];///选择新名字
    44         }
    45         else///这k个人首尾名字重合
    46             name[i+m-1]=name[i];
    47     }
    48 
    49     if(!flag)
    50         for(int i=1;i<=n;i++)
    51             cout<<"Aa"<<' ';
    52     else
    53     {
    54         ///找第一个YES
    55         int index;
    56         for(index=1;index<=n-m+1;index++)
    57             if(s[index]=="YES")
    58                 break;
    59         ///前面的人和他重名
    60         for(int i=index;i>=0;i--)
    61             name[i]=name[index];
    62 
    63         for(int i=1;i<=n;i++)
    64             cout<<name[i]<<' ';
    65     }
    66 }
    View Code

    D . Bear and Company(带技巧的dp)

    •题意

    有一种操作可交换相邻两个字母

    现给出一个S串,要求没有VK相连,求最小的操作数

    •思路

    在ljp的帮助下(tql...),终于AC了这个题

    s串中包含三种字母,V K和其他字母(因为其他字母无论是什么对VK都不产生影响)

    设dp数组$f[i][j][k][0/1]$

    前$i$个V,$j$个K,$k$个其他字母结尾不是$V$/不是$V$的最小操作数

    把V K和Other 分开

    for(int i=0;i<n;i++)
    {
    if(s[i]=='V') v[0].push_back(i); else if(s[i]=='K') v[1].push_back(i); else v[2].push_back(i); }

    首先看作一个空串,然后往后面添加字母

    V可以接在V K Other后面

    K可以接在K Other后面

    Other可以接在V K Other后面

    由于是接在后面的,那就要把本来应该在他后面但是现在在他前面的字母转移到后面

    并且这些字母与他只会进行一次交换

    例如ABCD中A转移到D后面,

    ABCD->BACD->BCAD->BCDA

    A只会和D进行一次交换

    添加V使得V在末尾影响$f[i][j][k][1]$

    添加K使得V不在末尾影响$f[i][j][k][0]$

    添加Other使得V不在末尾影响$f[i][j][k][0]$

    由于添加K和Other都是V不在末尾,如果两者都添加的话,一定要取最小值

    f数组必须初始化,因为有依赖关系

    •代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 ///v[0]:V  v[1]:K  v[2]:O
     4 vector<int> v[3];
     5 ///f[i][j][k][0/1]
     6 ///前i个V,j个K,k个O 尾位是否是V 的最小交换
     7 int f[80][80][80][2];
     8 int n;
     9 string s;
    10 int main()
    11 {
    12     cin>>n>>s;
    13     for(int i=0;i<n;i++)
    14     {
    15         if(s[i]=='V')
    16             v[0].push_back(i);
    17         else if(s[i]=='K')
    18             v[1].push_back(i);
    19         else
    20             v[2].push_back(i);
    21     }
    22 
    23     ///初始化
    24     for(int i=0;i<=v[0].size();i++)
    25         for(int j=0;j<=v[1].size();j++)
    26             for(int k=0;k<=v[2].size();k++)
    27                 f[i][j][k][0]=f[i][j][k][1]=0x3f3f3f3f;
    28     f[0][0][0][0]=0;
    29 
    30     int cnt=0;
    31     for(int i=0;i<=v[0].size();i++)
    32     {
    33         for(int j=0;j<=v[1].size();j++)
    34         {
    35             for(int k=0;k<=v[2].size();k++)
    36             {
    37                 if(i||j||k)
    38                 {
    39                     if(i)///0 V
    40                     {
    41                         ///V可以接在V K O后面
    42                         cnt=min(f[i-1][j][k][0],f[i-1][j][k][1]);
    43                         ///交换位置 K 1
    44                         for(int m=0;m<j;m++)
    45                             if(v[1][m]>v[0][i-1]) cnt++;
    46                         ///交换位置 O 2
    47                         for(int m=0;m<k;m++)
    48                             if(v[2][m]>v[0][i-1]) cnt++;
    49 
    50                         f[i][j][k][1]=cnt;
    51                     }
    52                     if(j)///1 K
    53                     {
    54                         ///K可以接在K O后面
    55                         cnt=f[i][j-1][k][0];
    56                         ///交换位置 V 0
    57                         for(int m=0;m<i;m++)
    58                             if(v[0][m]>v[1][j-1]) cnt++;
    59                         ///交换位置 O 2
    60                         for(int m=0;m<k;m++)
    61                             if(v[2][m]>v[1][j-1]) cnt++;
    62 
    63                         f[i][j][k][0]=cnt;
    64                     }
    65                     if(k)///2 O
    66                     {
    67                         ///O可以接在V K O后面
    68                         cnt=min(f[i][j][k-1][0],f[i][j][k-1][1]);
    69                         ///交换位置 V 0
    70                         for(int m=0;m<i;m++)
    71                             if(v[0][m]>v[2][k-1]) cnt++;
    72                         ///交换位置 K 1
    73                         for(int m=0;m<j;m++)
    74                             if(v[1][m]>v[2][k-1]) cnt++;
    75 
    76                         f[i][j][k][0]=min(f[i][j][k][0],cnt);///取最小值
    77                     }
    78                 }
    79             }
    80         }
    81     }
    82 
    83     int i=v[0].size(),j=v[1].size(),k=v[2].size();
    84     cout<<min(f[i][j][k][0],f[i][j][k][1])<<endl;
    85 }
    View Code
  • 相关阅读:
    SVN中的Trunk、Tag、Brance的用法
    开发下载地址汇集
    Hessian原理分析
    Java中间件:淘宝网系统高性能利器
    linux进阶
    常见的Hadoop十大应用误解
    搜索引擎汇总
    bat薪酬
    常用的快速Web原型图设计工具
    apache kafka消息服务
  • 原文地址:https://www.cnblogs.com/MMMinoz/p/11561321.html
Copyright © 2011-2022 走看看