VK Cup 2017 - Round 1
傳送門
A.?Bear and Friendship Condition(思維or完全圖判定)
?題意
給你n個(gè)人,m個(gè)朋友關(guān)系
朋友是會(huì)傳遞的,若A B是朋友,A C是朋友,則必須有B C的朋友關(guān)系
符合這個(gè)關(guān)系輸出YES,否則輸出NO
?思路
n個(gè)人,但凡是有朋友關(guān)系的,必定在同一個(gè)朋友圈內(nèi)
所以可以分成若干個(gè)朋友圈
在一個(gè)朋友圈內(nèi)部,若符合條件肯定是互為朋友
也就是 是一個(gè)完全圖
接下來就是判斷是否是完全圖了
舉個(gè)栗子:1234在一個(gè)朋友圈內(nèi),且符合條件
則人與朋友的對(duì)應(yīng)關(guān)系為
1與1 2 3 4為朋友
2與1 2 3 4為朋友
3與1 2 3 4為朋友
4與1 2 3 4為朋友
即,他們的朋友是完全相同的!
挨個(gè)去判斷朋友是否相同顯然時(shí)間復(fù)雜度不夠優(yōu)雅
只需要排序后,看第一個(gè)朋友是否相等就可以
O(n)變O(1)!
為什么呢? 因?yàn)槊總€(gè)人的朋友圈都要去查看一遍,如果A的朋友圈沒有B,但是B的朋友圈有A
那么,B和A的朋友圈肯定對(duì)不上,所以就輸出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數(shù)組是為了減少不必要的查看來減少時(shí)間 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 ///把自己也加進(jìn)自己的朋友圈 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 ///查看每個(gè)人的朋友圈 30 for(int i=1;i<=n;i++) 31 { 32 if(vis[i]) 33 continue; 34 ///自己的朋友圈和朋友的朋友圈對(duì)比 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個(gè)人,從1個(gè)人開始每k個(gè)一組
[1,k] [2,k+1]....
如果有重名的則NO,否則YES
根據(jù)NO和YES的結(jié)果輸出名字
名字首字母大寫,且1<=名字長(zhǎng)度<=10
?思路
因?yàn)槊珠L(zhǎng)度有限制,可能有很多人名字不同
所以首先預(yù)處理出不同名字來,注意計(jì)算名字個(gè)數(shù)
(這里踩了坑)
首先找到第一個(gè)YES為切入點(diǎn),后邊的名字可以由他得到
已經(jīng)確定了的名字不能再更改!否則會(huì)引起與前面的YES/NO不符 (這里也踩了坑
如果是YES的話就選擇新名字,否則選擇和這k個(gè)人的第一個(gè)人相同的名字(也就是首尾名字重合
然后再找第一個(gè)YES前面的人,從第一個(gè)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 ///預(yù)處理名字 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個(gè)人首尾名字重合 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 ///找第一個(gè)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)
?題意
有一種操作可交換相鄰兩個(gè)字母
現(xiàn)給出一個(gè)S串,要求沒有VK相連,求最小的操作數(shù)
?思路
在ljp的幫助下(tql...),終于AC了這個(gè)題
s串中包含三種字母,V K和其他字母(因?yàn)槠渌帜笩o(wú)論是什么對(duì)VK都不產(chǎn)生影響)
設(shè)dp數(shù)組$f[i][j][k][0/1]$
前$i$個(gè)V,$j$個(gè)K,$k$個(gè)其他字母結(jié)尾不是$V$/不是$V$的最小操作數(shù)
把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); }
首先看作一個(gè)空串,然后往后面添加字母
V可以接在V K Other后面
K可以接在K Other后面
Other可以接在V K Other后面
由于是接在后面的,那就要把本來應(yīng)該在他后面但是現(xiàn)在在他前面的字母轉(zhuǎn)移到后面
并且這些字母與他只會(huì)進(jìn)行一次交換
例如ABCD中A轉(zhuǎn)移到D后面,
ABCD->BACD->BCAD->BCDA
A只會(huì)和D進(jìn)行一次交換
添加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數(shù)組必須初始化,因?yàn)橛幸蕾囮P(guān)系
?代碼
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個(gè)V,j個(gè)K,k個(gè)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?
轉(zhuǎn)載于:https://www.cnblogs.com/MMMinoz/p/11561321.html
總結(jié)
以上是生活随笔為你收集整理的VK Cup 2017 - Round 1的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 某业务付费统计脚本问题排查
- 下一篇: Codeforces Round #58