7月2日训练总结
900——1000 5道
A. Anti Light's Cell Guessing
题意大概是在一个行列确定的坐标系里,最少用几个点可以唯一确定一个点
思路就是判断行列的最小值是否为1,是1的话,最多一个点就可以确定,否则两个点即可。
注意:1*1的方格需要的点是0,故需要特判
解决代码:
void solve()
{
int n, m;
cin >> n >> m;
if(n == m && n == 1) cout << 0 << endl;
else
if(min(n, m) > 1) cout << 2 << endl;
else cout << 1 << endl;
}
C. Minimum Extraction
题意是每次从数组中取出最小值,然后剩下的所有数全减去最小值,问最小值最大时为多少
思路:其实就是道差分,将数组从小到大排序后,建立差分数组,然后遍历找到最大值即可。
证明:
例如:3 2 -4 -2 0
排序后为 -4, -2, 0, 2 , 3
差分数组为2, 2, 2, 1
故其最大值为2
原因是每次减去最小值,是整个数组进行的,所以数组中两数的差值不变。故而两数的最小值也不变,排序后差分得到的数,都是本数变成最小数的最大值。而这即为所求
解决代码:
const int N = 200010, INF = 0x3f3f3f3f;
int a[N], b[N];
void solve()
{
int n;
cin >> n;
for(int i = 1; i <= n; i++) cin >>a[i];
sort(a + 1, a + 1 + n);
int ans = -INF;
for(int i = 1; i <= n; i++) b[i] = a[i] - a[i - 1], ans = max(ans, b[i]);
cout << ans <<endl;
}
B. Odd Grasshopper
大意是给你初始位置,和移动次数,以你所在点为准,若是偶数,则往左跳,否则往右跳,跳的距离是跟着次数来的,比如第一次,跳一格,第二次跳两格,要求最后所在的位置是哪
通过观察可知,这个游戏的位置移动是周期性的,每跳4次就会回到初始位置。故而可以直接将次数mod4,然后模拟后续过程即可。但是我在写的时候将所有步骤全想清楚了,代码异常繁琐,也不需要分奇偶
解决代码:
void solve()
{
int x, n;
cin >> x >> n;
int ans = 0;
if(x % 2 == 0)
{
if(n % 4 == 0) ans = x;
else if(n % 4 == 1)
{
ans = x - n;
}
else if(n % 4 == 2) ans = x + 1;
else if(n % 4 == 3) ans = x + 1 + n;
}
else{
if(n % 4 == 0) ans = x;
else if(n % 4 == 1) ans = x + n;
else if(n % 4 == 2) ans = x - 1;
else if(n % 4 == 3) ans = x - 1 - n;
}
cout << ans <<endl;
}
A. AB Balance
题意是,给一串只含AB的字符串,输出修改后子串“AB”,与子串“BA”数量相等的字符串。
我写的时候思路是扫描一遍字符串,统计AB和BA出现的次数,等于返回原串,如果AB多于BA,如果第一个字符为a就改成b,如果最后一个字符为b则改成a,本意是减少一个ab。因为经过观察,ab和ba的数量之差不可能大于1。如果BA多于AB,则同理,反过来即可。
但看了官方题解之后,这题的规律其实就是:如果第一个字符和最后一个字符相等,那么AB和BA的数量一定相等,否则不等
解决代码:
void solve()
{
string s;
cin >> s;
int len = s.size();
int cnab = 0, cnba = 0;
for(int i = 0; i < len - 1; i ++)
{
if(s[i] == 'a' && s[i + 1] == 'b') cnab ++;
if(s[i] == 'b' && s[i + 1] == 'a') cnba ++;
}
if(cnab == cnba) cout << s << endl;
else {
if(cnab > cnba)
{
if(s[0] == 'a') s[0] = 'b';
else if(s[len - 1] == 'b') s[len - 1] = 'a';
}
else {
if(s[0] == 'b') s[0] = 'a';
else if(s[len - 1] == 'a') s[len - 1] = 'b';
}
cout << s << endl;
}
}
B. Reverse Sort
题意是给一个01数组,然后选择其中递减的序列,排序翻转再依次放进被选择的位置,问需要几次,和每次选择用的下标是什么
自己写的时候没想到,后来看题解
思路是将数组排序后,观察现在和原来数组不同的地方,然后将下标存进vector中,一次即可解决
原理是现在和原来数组不同只可能是01,10两种情况,需要翻转的数列必然是10类的,符合题目要求,且10数量必然成对
解决代码:
void solve()
{
int n;
cin >> n;
string s;
cin >> s;
string t;
t = s;
sort(t.begin(), t.end());
if(s == t) cout << 0 << endl;
else{
cout << 1 <<endl;
vector<int> v;
for(int i = 0; i < s.size(); i ++)
{
if(s[i] != t[i]) v.push_back(i + 1);
}
cout << v.size() << ' ';
for(auto i : v) cout << i << ' ';
cout << endl;
}
}
1100——1200 3题
B. Odd Swap Sort
题意是选择两个相邻的数,如果他们相加为奇数,则可以交换,问是否能用若干次操作使数组以递增顺序排序
看的题解,刚开始想的用冒泡,可是超时了
思路:两个数相加为奇数,说明两个数的奇偶性不同。也就是说只有奇偶性不相同的才能交换,奇偶性相同的不能交换。
由此可以推出,如果奇偶性相同的数不是递增,那么必然不能完成,否则一定可以。
解决代码:
void solve()
{
int n;
cin >> n;
vector<int> e, o;
for(int i = 1; i <= n; i ++)
{
int x;
cin >> x;
if(x % 2) e.push_back(x);
else o.push_back(x);
}
if(is_sorted(e.begin(), e.end()) && is_sorted(o.begin(), o.end())) puts("Yes");// is_sorted函数是用来判断是否数组有序的,有序true,无序false
else puts("No");
}
C. Andrew and Stones
题意是选择三个下标a < b < c,每次可以从b所在点中取两个石头,一个放到a,一个放到c,当然前提是b要有两个石头,否则放不了。问是否可以通过一系列操作使石头全在数组第一个点和最后一个点中
看的题解
思路:假如有三个石头,第二个石头是奇数,则不可能,假如中间有若干个数,但都为1,则不可能。否则可能。因为每回都可以通过放石头使原来为奇数个石头的点变成偶数,从而放完石头
解决代码:
void solve()
{
int n;
cin >> n;
int maxv = -INF, ans = 0;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 2; i < n; i ++) maxv = max(maxv, a[i]);
if(maxv == 1 || n == 3 && a[2] % 2 == 1)
{
cout << -1 << endl;
return ;
}
for(int i = 2; i < n; i ++) ans += (a[i] + 1) / 2;
cout << ans << endl;
}
C. Differential Sorting
题意是给a < b < c三个点,问是否能通过将b - c所得值赋给a,来达到使整个数组递增的目的,如果可以输出需要几次和每次使用的下标
思路:如果从前向后遍历的话,c点的选取会很困难,所以从后先前遍历。c点开始是最后一个点,如果遇到比c更大的点,那么将之赋给c,b点是a点后面的一个点,这样可以保证a点被赋值后必然小于后面的点。
如果最后两个点是递减的那么肯定不可能,因为无法改变倒数第二个点的值。如果a点大于b点,且b点减去最大的c点都无法小于b点,那么说明a点无论如何都会大于b点,则不可能。
解决代码:
void solve()
{
int n;
cin >> n;
int cnt = 0;
for(int i = 1; i <= n; i ++) cin >> a[i];
if(a[n - 1] > a[n])
{
cout << -1 << endl;
return ;
}
for(int i = n - 2, j = n - 1, k = n; i >= 1; i --, j--)
{
if(a[i] > a[j])
{
if(a[j] - a[k] > a[j])
{
cout << -1 << endl;
return ;
}
else{
a[i] = a[j] - a[k];
ss[cnt].x = i, ss[cnt].y = j, ss[cnt].z = k;
cnt ++;
}
}
if(a[k] < a[j]) k = j;
}
cout << cnt << endl;
for(int i = 0; i < cnt; i++)
cout << ss[i].x << ' ' << ss[i].y << ' ' << ss[i].z << endl;
}
总结:
900——1000的题目有时做的也磕磕绊绊,最后大都能想出来,但是时间耗费太长,思维不行。
1100——1200的题目看着都差不多,基本思路都有,但是如何优化需要好好想想,这种类型的题基本需要一点点算法和思维的敏捷,看能否找到最优解法,思维不够。
目前解决思路:多刷题,多总结。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步