VK Cup 2017 - Round 1
傳送門
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);elsev[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?
轉載于:https://www.cnblogs.com/MMMinoz/p/11561321.html
總結
以上是生活随笔為你收集整理的VK Cup 2017 - Round 1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 某业务付费统计脚本问题排查
- 下一篇: Codeforces Round #58