传送门
题目大意:
有t组样例,
每组n个数字,可以给n个数字后添加任意个不限大小的正整数。使得所有数字的平均数为1。
思路:
分类讨论,当n个数字之和为n时,不用添加任何数字。
当n个数字之和小于n时,可以添加一个整数使得n+1个数字之和为n+1,所以答案为1
当n个数字之和大于n时,在最后一直添加0,直到满足题意,所以答案为n-ans
代码:
#include<bits/stdc++.h>
using namespace std;
#define debug(a) cout << #a << ": " << a << endl;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void solve()
{
int n;
cin >> n;
int ans = 0;
for(int i = 1,x;i <= n;++i) {
cin >> x;
ans += x;
}
if(ans < n) cout << 1 << endl;
else if(ans == n) cout << 0 << endl;
else cout << ans-n << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
题目总结:
思维水题
传送门
题目大意:
有t组样例,每组四个数字,n,m,x,y;
代表n*m的矩阵,有一个人在x,y的位置上。
在矩阵中放置2个皮球,问为了这个人将两个气球捡到并回到原位置的步数最大,两个皮球应该放在哪里。这个人只能上下左右行走。
思路:
首先放置一个气球的话,那么会把气球放在离当前人所在位置最远的位置。
当人走到那个位置的时候,离那个位置最远的位置就是另一个气球的位置。
所以枚举四个端点可以得到结果。
代码:
#include<bits/stdc++.h>
using namespace std;
#define debug(a) cout << #a << ": " << a << endl;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void solve()
{
int n,m,x,y;
cin >> n >> m >> x >> y;
int ans1 = fabs(n-x)+fabs(m-y);
int ans2 = fabs(1-x)+fabs(m-y);
int ans3 = fabs(n-x)+fabs(1-y);
int ans4 = fabs(1-x)+fabs(1-y);
int ma = max(ans1,max(ans2,max(ans3,ans4)));
if(ma == ans1 || ma == ans4) {
cout << n << ' ' << m << ' ' << 1 << ' ' << 1 << endl;
}
else {
cout << 1 << ' ' << m << ' ' << n << ' ' << 1 << endl;
}
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
题目总结:
思维水题
传送门
题目大意:
有t组样例,
每组样例给出n个值,如果存在(1<=i<n)使得hi<hi+1,记做一个幸运点,问在第一个数和最后一个数字相差最小的情况下,最多幸运点的排序。
思路:
首先对于所有数值进行排序,那么我们可以找到并确认第一个数字和最后一个数字。然后从第一个数字的位置开始一直输出到最后,再从a[1]输出到最后一个数字的位置。我们可以证明一般情况下这会得到两个上升子段以及一个最大断层,这就是可以得到最多幸运点的情况。
代码:
#include<bits/stdc++.h>
using namespace std;
#define debug(a) cout << #a << ": " << a << endl;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int maxn = 2e5+10;
int a[maxn];
void solve()
{
int n;
cin >> n;
for(int i = 1;i <= n;++i) {
cin >> a[i];
}
sort(a+1,a+1+n);
int mi = 0x3f3f3f3f,cn = 0;
for(int i = 2;i <= n;++i) {
if(a[i]-a[i-1] < mi) {
mi = a[i]-a[i-1];
cn = i;
}
}
cout << a[cn-1] << ' ';
for(int i = cn+1;i <= n;++i) {
cout << a[i] << ' ';
}
for(int i = 1;i < cn-1;++i) {
cout << a[i] << ' ';
}
cout << a[cn] << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
题目总结:
思维水题
传送门
题目大意:
有t组样例,每组一个整数n
两个人轮流执行减去当前数字的除数(不包括1和自身)
两个人都足够聪明,给定一个数求谁会赢
思路:
博弈题,两个人一定会有一个统一的拆数标准。
首先,对于数字分析,我们不难发现如果数字分为偶数乘以一个素数,那么就会被拆成奇数乘以当前素数,这回保证当前人会赢掉比赛。我们发现,奇数成素数和偶数乘素数的结果是确定的。
其次,对于2这个特殊素数,我们要进行分析,如果不是2的n次方,那么所乘素数一定不为2,可以不判断。对于2的n次方,我们发现2的奇数次方,第一个人输,偶数次方第一个人赢。
得到结论。
代码:
#include<bits/stdc++.h>
using namespace std;
#define debug(a) cout << #a << ": " << a << endl;
#define LL long long
#define IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
void solve()
{
int n;
cin >> n;
bool si = true;
for(int i = 2;i <= sqrt(n);++i) {
if(n%i == 0) {
si = false;
break;
}
}
if(si) {
cout << "Bob" << endl;
return ;
}
int m = n,cnt = 0;
while(m%2 == 0) m/=2,cnt++;
if(m == 1) {
if(cnt%2 == 1) cout << "Bob" << endl;
else cout << "Alice" << endl;
return ;
}
if(n%2 == 1) {
cout << "Bob" << endl;
}
else
cout << "Alice" << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--){
solve();
}
return 0;
}
题目总结:
博弈题中比较有代表性的一类题。
对于数字的分析要有一定的敏感性。
传送门
题目大意:
给定一个长为n的字符串s,可以对s进行两种操作:
s.pop_back(),s= s+s;
问能够得到的字典序最小的长为k的字符串
思路:
从前向后遍历,如果当前位置与第一个位置相同则我们暂且认为它是一个位置复制过来的,然后向后遍历,如果当前位置大于对应位置的字符则,我们得到了s=s+s,的最小s,循环输出到第k个位置即可,如果小于对应位置,则重新从当前位置与第一个位置匹配。可以证明,最小更新子串得到的字符串就是最小的字符串。
代码:
#include<bits/stdc++.h>
using namespace std;
#define LL long long
map<int,int> mp;
int main()
{
int n,k;
cin >> n >> k;
int index = 0;
string s;
cin >> s;
string ans = "";
ans += s[0];
for(int i = 1;i < s.length();++i) {
if(s[i] > ans[index])
break;
ans += s[i];
if(s[i] == ans[index])
index++;
else
index = 0;
}
while(index != 0) {
ans.pop_back();
index--;
}
for(int i = 0;i < k;++i)
cout << ans[i%ans.length()];
cout << endl;
}
题目总结:
E1和E2的数据范围不一样,解题的思路一致,对于小的数据我们可以采取截取字符串的方式匹配,逐个匹配算是一种复杂度的优化。