A-Arithmetic Array
题意:给定一个数组,一次可以给数组增加一个非负的元素,问最少需要增加多少次,可以使数组满足:数组元素之和等于数组的长度
思路:枚举初始给定数组之和。
若小于数组长度,则再增加一个整数即可(肯定存在这样的一个正数);
若等于数组长度,则不用添加元素;
若大于数组长度,则需要添加(数组之和减数组长度)个0.
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| #include <algorithm> #include <iostream> #include <cstdio> #include <iterator> #include <vector> #include <cstring> #include <string> #include <cmath> #include <deque> #include <queue> #include <map> #include <unordered_map> #include <set> #include <stack>
using namespace std; typedef long long ll; #define inf 0x3f3f3f3f #define endl "\n" #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #define debug(x) cout<<"**"<<x<<"**"<<endl #define mem(a, b) memset(a, b, sizeof a) const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; const int N = 1e4 + 10;
int main() { #ifndef ONLINE_JUDGE freopen("in.in", "r", stdin); freopen("out.out", "w", stdout); #endif IOS int T; cin>>T; while(T--) { int n; cin>>n; ll sum = 0, ans; for(int i = 0; i < n; i++) { int x; cin>>x; sum += x; } if(sum < n) ans = 1; else if(sum == n) ans = 0; else ans = sum-n; cout<<ans<<endl; } return 0; }
|
B-Bad Boy
题意:一个人站在n×m的方格中(x, y)处,让你在方格中挑选两个位置放置两个悠悠球,然后这个人去捡悠悠球再回到原位置,问这两个悠悠球放在哪能让他走的路程最大。
思路:第一个球放在离他现在位置最远的地方,第二个球放在离第一个球最远的位置(其实就是某两个顶点处)
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| #include <algorithm> #include <iostream> #include <cstdio> #include <iterator> #include <vector> #include <cstring> #include <string> #include <cmath> #include <deque> #include <queue> #include <map> #include <unordered_map> #include <set> #include <stack>
using namespace std; typedef long long ll; #define inf 0x3f3f3f3f #define endl "\n" #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #define debug(x) cout<<"**"<<x<<"**"<<endl #define mem(a, b) memset(a, b, sizeof a) const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; const int N = 1e4 + 10;
int main() { #ifndef ONLINE_JUDGE freopen("in.in", "r", stdin); freopen("out.out", "w", stdout); #endif IOS int T; cin>>T; while(T--) { int n, m, xx, yy; int x1, y1, x2, y2; cin>>n>>m>>xx>>yy; if(xx <= (n+1)/2) x1 = n; else x1 = 1; if(yy <= (m+1)/2) y1 = m; else y1 = 1; if(x1 == n) x2 = 1; else x2 = n; if(y1 == m) y2 = 1; else y2 = m; cout<<x1<<" "<<y1<<" "<<x2<<" "<<y2<<endl; } return 0; }
|
C-Challenging Cliffs
题意:给定一个数组,每个数组元素代表一座山,值代表高度。从i -> i+1, 如果$h_{i} <= h_{i+1}$,则贡献值加1。让你重新排列数组,找出贡献值最大的排列,同时还要满足数组第一个值和最后一个值的差值是最小的。
思路:排个序。找出最小差值,然后按照排序之后的顺序分段输出即可保证贡献值最大。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <algorithm> #include <iostream> #include <cstdio> #include <iterator> #include <vector> #include <cstring> #include <string> #include <cmath> #include <deque> #include <queue> #include <map> #include <unordered_map> #include <set> #include <stack>
using namespace std; typedef long long ll; #define inf 0x3f3f3f3f #define endl "\n" #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #define debug(x) cout<<"**"<<x<<"**"<<endl #define mem(a, b) memset(a, b, sizeof a) const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; const int N = 1e4 + 10;
int main() { #ifndef ONLINE_JUDGE freopen("in.in", "r", stdin); freopen("out.out", "w", stdout); #endif IOS int T; cin>>T; while(T--) { int n; cin>>n; int a[n+1]; for(int i = 1; i <= n; i++) cin>>a[i]; sort(a+1, a+n+1); int minn = a[2]-a[1], id = 1; for(int i = 3; i <= n; i++) { if(a[i]-a[i-1] < minn) { minn = a[i]-a[i-1]; id = i-1; } } cout<<a[id]<<" "; for(int i = id+2; i <= n; i++) cout<<a[i]<<" "; for(int i = 1; i < id; i++) cout<<a[i]<<" "; cout<<a[id+1]<<endl; } return 0; }
|
D-Deleting Divisors
题意:Alice和Bob在玩游戏,Alice和Bob又在玩游戏,Alice和Bob总在玩游戏(o_o)
给定一个数字n,每次可以拿走一个n的除数(不能是1或n),n相应减少。无法再拿走除数时就输。Alice先手。
(参考了这位的博客:链接)
思路:博弈论嘛,先分析出必败态为最后剩下一个质数(质数除了2都是奇数)。然后枚举情况(可以打表观察规律,这样推规律的时候就会方向清晰一点)
一、Alice先手拿到偶数。
(1)这个偶数由奇数*偶数组成:在最优选择下,Alice会减一个奇数的除数,剩下一个奇数给Bob,Bob只能减奇数的除数(因为没有偶数的除数),剩下一个偶数给Alice,开始循环。。。则Alice必胜
(2)这个偶数由偶数*偶数组成(可以表示为$2^{n}$):在最优选择下,Alice会选择减去$2^{n-1}$,剩下$2^{n-1}$给Bob(不这样减的话,Bob一定拿到奇数*偶数,则Bob就一定赢),Bob也同样会继续选择减去$2^{(n-1)-1}$。那么最终状态就是:如果n是偶数,则Bob拿到2,Bob输;如果n是奇数,则Alice拿到2,Alice输。
二、Alice先手拿到奇数
Alice只能减去一个奇数的除数,则Bob拿到由奇数*偶数组成的偶数,即Alice必输。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #include <algorithm> #include <iostream> #include <cstdio> #include <iterator> #include <vector> #include <cstring> #include <string> #include <cmath> #include <deque> #include <queue> #include <map> #include <unordered_map> #include <set> #include <stack>
using namespace std; typedef long long ll; #define inf 0x3f3f3f3f #define endl "\n" #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #define debug(x) cout<<"**"<<x<<"**"<<endl #define mem(a, b) memset(a, b, sizeof a) const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; const int N = 1e4 + 10;
int main() { #ifndef ONLINE_JUDGE freopen("in.in", "r", stdin); freopen("out.out", "w", stdout); #endif IOS int T; cin>>T; while(T--) { int n; cin>>n; if(n&1) cout<<"Bob"<<endl; else { int cnt = 0; while(n%2 == 0) { n /= 2; cnt++; } if(n != 1) cout<<"Alice"<<endl; else { if(cnt&1) cout<<"Bob"<<endl; else cout<<"Alice"<<endl; } } } return 0; }
|
E-Erase and Extend (Easy Version)
题意:给定一个长度为n的字符串s,可以无限次进行两种操作:删除最后一个元素或者使s = s+s。求通过这两种操作,可以得到的长度为k的最小的字符串。
思路:建议先看一遍代码。最终的答案肯定是s的一个前缀子串的重复。然后证明这种做法的合理性:(cnt代表:从s[0]开始的,最终结果中的前缀子串的长度)。纯证明肯定是没有举栗子更好理解。
(1)s[i] > s[i%cnt]
第i个元素比前缀子串中对应位置的元素大,显而易见该结束了
举个栗子:dcadcb 这种情况就是:目前的最优字串为dca,然后遇到了b,b>a,如果结束,最优字串重复为:dcadcadca,否则就是:dcadcbdca。肯定前面的是要小的,所以说明确实该结束了。
(2)s[i] < s[i%cnt]
第i个元素比最优前缀中对应位置的元素小,那就说明最优字串可以扩充s[i]。
举个栗子:dcbdca 这种情况就是:目前的最优字串为dcb,然后遇到了a,a<b,如果扩充,最优字串重复就是 dcbdcadcbdca,否则就是 dcbdcbdcbdcb,肯定是前面小,所以最优字串应该扩充
(3)s[i] == s[i%cnt]
这种情况是不能break的。因为不知道s[i+1]和s[(i+1)%cnt]的大小情况。
举个栗子:dbda ,等于说现在到了第二个d的位置,现在最优字串是db,如果break,第一种情况的答案就是dbdbdbdb,和dbdadbda的比较,显见是不能break;
再举个栗子:dbdc,和上面差不多,break后就是dbdbdbdb,和dbdcdbdc比较确实是更优的。
综上所述不能break。同样的道理,也不能更新最优字串到s[i]。
大家举举栗子就会发现很好理解。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <algorithm> #include <iostream> #include <cstdio> #include <iterator> #include <vector> #include <cstring> #include <string> #include <cmath> #include <deque> #include <queue> #include <map> #include <unordered_map> #include <set> #include <stack>
using namespace std; typedef long long ll; #define inf 0x3f3f3f3f #define endl "\n" #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #define debug(x) cout<<"**"<<x<<"**"<<endl #define mem(a, b) memset(a, b, sizeof a) const double eps = 1e-6; const double pi = acos(-1.0); const int mod = 1000000007; const int N = 1e4 + 10;
int main() { #ifndef ONLINE_JUDGE freopen("in.in", "r", stdin); freopen("out.out", "w", stdout); #endif IOS int n, k; cin>>n>>k; string s; cin>>s; int cnt = 1; for(int i = 0; i < n; i++) { if(s[i] > s[i%cnt]) break; if(s[i] < s[i%cnt]) cnt = i+1; } for(int i = 0; i < k; i++) cout<<s[i%cnt]; return 0; }
|
F-Erase and Extend (Hard Version)
E的代码的时间复杂度是O(n),可以直接过F。