涵盖知识点:数学、贪心、瞎搞
比赛链接:
http://codeforces.com/contest/1305/
A:Kuroni and the Gifts
题意:问怎么排两个数组使得每一位的和都不相同。(保证原本两个数组内不存在相同元素)
题解:全部从小到大排序即可。
Accept Code:
1 //A 2 #include <bits/stdc++.h> 3 using namespace std; 4 const int maxn=110; 5 int a[maxn],b[maxn]; 6 int main(){ 7 int t; 8 cin>>t; 9 while(t--){ 10 int n; 11 cin>>n; 12 for(int i=0;i<n;i++) 13 cin>>a[i]; 14 for(int i=0;i<n;i++) 15 cin>>b[i]; 16 sort(a,a+n); 17 sort(b,b+n); 18 for(int i=0;i<n;i++) 19 cout<<a[i]<<" "; 20 cout<<" "; 21 for(int i=0;i<n;i++) 22 cout<<b[i]<<" "; 23 cout<<" "; 24 } 25 return 0; 26 }
B:Kuroni and Simple Strings
题意:规定一个长度为2n的串当且仅当前n个为'('且后n个为')'时为完美串。现给一个串,从中取出子序列,当且仅当子序列为完美串时可删除。问最少删几次可以使得串不可删。
题解:贪心、从左向右找左括号,从右向左找右括号尽量匹配即可。
Accept Code:
1 //B 2 #include <bits/stdc++.h> 3 using namespace std; 4 vector<int> v; 5 int main(){ 6 string s; 7 cin>>s; 8 int l=0,r=s.length()-1; 9 while(1){ 10 while(s[l]!='('&&l<s.length()-1)l++; 11 while(s[r]!=')'&&r>0)r--; 12 if(r<=l)break; 13 v.push_back(l); 14 v.push_back(r); 15 l++,r--; 16 } 17 if(v.empty()){ 18 cout<<0<<" "; 19 return 0; 20 } 21 cout<<"1 "; 22 cout<<v.size()<<" "; 23 sort(v.begin(),v.end()); 24 for(auto i:v){ 25 cout<<i+1<<" "; 26 } 27 cout<<" "; 28 return 0; 29 }
C:Kuroni and Impossible Calculation
题意:求对m取模。(m<1000)
题解:考虑两种情况:
(1)n≤m:暴力。
(2)n>m:答案为0.
证明:所有数对m取模仅有m中取值。若n>m,则一定有两个数对m同余,相减可以被整除。
Accept Code:
1 //C 2 #include <bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 const int maxn=2e5+10; 6 ll a[maxn]; 7 int main(){ 8 int n,m; 9 cin>>n>>m; 10 for(int i=1;i<=n;i++){ 11 cin>>a[i]; 12 } 13 if(n>m){ 14 cout<<0<<" "; 15 return 0; 16 } 17 ll ans=1; 18 for(int i=1;i<=n;i++){ 19 for(int j=i+1;j<=n;j++){ 20 ans*=abs(a[j]-a[i]); 21 ans%=m; 22 } 23 } 24 cout<<ans<<" "; 25 return 0; 26 }
D:Kuroni and the Celebration
题意:互动题,每次查询可以得到两个点的LCA。让你保证在n/2次查询内查到根节点。
题解:瞎搞。每次选两个叶节点,对于得出的结果如果为其中一个节点,那么它一定为根,反之删除这两个节点,重新选择任意两个叶节点。一定可以在规定次数内找到。
Accept Code:
1 //D 2 #include <bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 const int maxn=1010; 6 vector<int> edg[maxn]; 7 int deg[maxn]; 8 bool vis[maxn]; 9 int main(){ 10 int n; 11 cin>>n; 12 for(int i=0;i<n-1;i++){ 13 int u,v; 14 cin>>u>>v; 15 edg[u].push_back(v); 16 edg[v].push_back(u); 17 deg[u]++,deg[v]++; 18 } 19 queue<int> q; 20 for(int i=1;i<=n;i++){ 21 if(deg[i]==1) 22 q.push(i); 23 } 24 for(int k=1;k<=n/2;k++){ 25 int x=q.front(); 26 q.pop(); 27 int y=q.front(); 28 q.pop(); 29 cout<<"? "<<x<<" "<<y<<" "; 30 cout.flush(); 31 int u; 32 cin>>u; 33 if(u==x||u==y){ 34 cout<<"! "<<u<<" "; 35 return 0; 36 } 37 vis[x]=true; 38 for(auto v:edg[x]){ 39 if(!vis[v]){ 40 deg[v]--; 41 if(deg[v]==1) 42 q.push(v); 43 } 44 } 45 vis[y]=true; 46 for(auto v:edg[y]){ 47 if(!vis[v]){ 48 deg[v]--; 49 if(deg[v]==1) 50 q.push(v); 51 } 52 } 53 } 54 for(int i=1;i<=n;i++){ 55 if(!vis[i]){ 56 cout<<"! "<<i<<" "; 57 return 0; 58 } 59 } 60 return 0; 61 }
E:Kuroni and the Score Distribution
题意:安排n个严格递增的分数使得的组数恰好等于m。
题解:对于前i个数字当且仅当时可以获得的三元组最多,为。所以m依次减去贡献直到不可减。关键是怎么根据剩余的m构造出第i+1个数。后面随便取,瞎搞就行了。具体实现看代码。
Accept Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=5010; 5 int a[maxn]; 6 int main(){ 7 int n,m; 8 cin>>n>>m; 9 int i=1; 10 for(;i<=n;i++){ 11 a[i]=i; 12 if(m<(i-1)/2) 13 break; 14 m-=(i-1)/2; 15 } 16 if(i>n&&m){ 17 cout<<"-1 "; 18 return 0; 19 } 20 a[i]=(a[i-2]+a[i-1]+2)-2*m; 21 for(i++;i<=n;i++){ 22 a[i]=i*10000+77777777; 23 } 24 for(i=1;i<=n;i++){ 25 cout<<a[i]<<" "; 26 } 27 cout<<" "; 28 return 0; 29 }
F:Kuroni and the Punishment
题意:给定一个n个数的数组,每次操作可以使其中一个数字加一或者减一。问最少几次操作可以使所有数字的gcd不为1.
题解:人间迷惑行为,究极瞎搞。首先理论最大答案为n。因为可以取2为gcd,后面只要把所有数字变成偶数即可。然后随机排列一下,随便抓几个数字对每个数字的-1到+1范围内取素因子,然后对每个素因子扫描一下所有数字至少增加次数,求和取最小值即可。
Accept Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long ll; 5 6 mt19937 mt(chrono::steady_clock::now().time_since_epoch().count()); 7 8 const int maxn = 2e5+10; 9 10 int n; 11 ll a[maxn],ans; 12 13 vector<ll> fact(ll x) { 14 vector<ll> pf; 15 for (int y = 2; 1ll*y * y <= x; y++) { 16 if (x % y == 0) { 17 while (x % y == 0) x/= y; 18 pf.push_back(y); 19 } 20 } 21 if (x != 1) pf.push_back(x); 22 return pf; 23 } 24 25 void upd(ll x) { 26 ll res = 0; 27 for (int i = 0; i < n; i++) { 28 if (a[i] < x) { 29 res += x - a[i]; 30 continue; 31 } 32 ll r = a[i] % x; 33 res += min(r, x - r); 34 } 35 ans=min(ans,res); 36 } 37 38 void test(ll x) { 39 vector<ll> pf = fact(x); 40 for (ll p : pf) 41 upd(p); 42 } 43 44 int main() { 45 cin >> n; 46 for (int i = 0; i < n; i++) cin >> a[i]; 47 shuffle(a, a + n, mt); 48 ans = n; 49 for (int i = 0; i < min(n, 40); i++) { 50 test(a[i]); 51 if (a[i] > 1) test(a[i] - 1); 52 test(a[i] + 1); 53 } 54 cout << ans << ' '; 55 return 0; 56 }