题目大意
假定第一行给出如下:abcdefghijklmnopqrstuvwxyz
我们可以发现a在第一个位置,c在第三个位置
那么我们要打出ac这个字符串手指就需要移动2下
问给出一个字符串,手指需要移动几下才能打出来
解题思路
通过一维数组记录每一个字符的位置,然后每两个相邻的字符通过位置差可以得到手指移动的次数。
解题代码
#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
#define debug(a) cout << #a << ' ' << a << endl;
void in_out()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
}
int a[30];
void solve()
{
string s;
cin >> s;
for(int i = 0;i < s.length();++i) {
a[s[i] - 'a'] = i;
}
string s1;
cin >> s1;
int ans = 0,pre = a[s1[0]-'a'];
for(int i = 1;i < s1.length();++i) {
ans = ans + fabs(a[s1[i] - 'a'] - pre);
// cout << ans << endl;
pre = a[s1[i] - 'a'];
}
cout << ans << endl;
}
int main()
{
IO;
int t;
cin >> t;
while(t--) {
solve();
}
}
题目大意
给出两个数a,b
a是初始位置,b是移动次数
假如当前位置是奇数会向右移动i个单位(i表示第i次移动)
假如当前位置是偶数会向左移动i个单位 (i表示第i次移动)
问b次移动后,当前位置是哪里
解题思路
对于模拟题,可以通过模拟题意的执行,来寻找规律。
具体规律见代码。
解题代码
#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
#define debug(a) cout << #a << ' ' << a << endl;
#define LL long long
void in_out()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
}
void solve()
{
LL x0,n;
cin >> x0 >> n;
LL ans = 0;
if(x0%2 == 0) {
if(n%4 == 0) cout << x0 << endl;
else if(n%4 == 1) cout << x0-n << endl;
else if(n%4 == 2) cout << x0+1ll << endl;
else cout << x0+n+1ll << endl;
}
else {
if(n%4 == 0) cout << x0 << endl;
else if(n%4 == 1) cout << x0+n << endl;
else if(n%4 == 2) cout << x0-1ll << endl;
else cout << x0-n-1ll << endl;
}
}
int main()
{
IO;
int t;
cin >> t;
while(t--) {
solve();
}
}
题目大意
给出一个长为n的数组,我们每次可以将数组中的最小数取出来,然后给剩余数字都减去取出的数字。
问数组在变换过程中,出现的最小值的最大数是多少。
解题思路
我们现提出一个值得去摒弃的假思路,然后再推翻它求出正解。
首先,当n为1时,结果很显然为a[1]
当n不为1时,很显然结果不会是一个负数。
那么我们将所有负数都取出来,这就是结果吗?
显然,如果通过感觉我们也许会认为如果取出一个正数,那么所有数字都会降低,是不划算的。
但是,在[1,2,7]这个数组中我们却发现了最佳的答案是4而不是1
这是因为,7在降低的过程中,数组的最小值也被去除,如果7下降的值大于了数组当前的最小值,那么我们就可以取出最小值来提高数组当中的最小值
通过多次举例,我们会发现并没有出现一个完美的贪心思路。
查看数据范围,我们发现完全可以枚举每一个阶段的数组最小值,这也正是此题的正解。
解题代码
#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
#define LL long long
const int maxn = 2e5+10;
LL a[maxn];
void in_out()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
}
void solve()
{
int n;
cin >> n;
priority_queue<LL,vector<LL>,greater<LL> > q;
while (q.size() > 0) q.pop();
for(int i = 1;i <= n;++i) cin >> a[i],q.push(a[i]);
LL ans = -1e9-10,pre = 0;
while (q.size() > 0)
{
LL x = q.top();
q.pop();
x += pre;
ans = max(ans,x);
// cout << "ans:" << ans << endl;
pre -= x;
}
cout << ans << endl;
}
int main()
{
// in_out();
IO;
int t;
cin >> t;
while (t--)
{
solve();
}
}
题目大意
题中会给出一个数组,每一个数组元素都有一个属性红或者蓝
蓝属性元素可以降低到任意值,红属性元素可以增加到任意值
问给出的数组通过红蓝变换能否实现1到n每个数字只出现一次
解题思路
这里有一个重要的思路,就是反向思考。
题中问什么情况可,我们就去想什么情况不可
如果在蓝元素中,出现了1,1,2,3就不可以
为什么呢?因为如果前m个蓝色元素出现了两次小于m的元素,那么数组无论如何变幻,小于m的元素数量永远大于m个,这说明前m-1个元素必定会有重复的。
在红色元素中,也有同样的道理。
仔细思考,除了这两种情况,还有其他情况会出现不可行状态吗?
解题代码
#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
#define LL long long
const int maxn = 2e5+10;
int a[maxn];
vector<int> l,r;
void in_out()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
}
void solve()
{
int n;
cin >> n;
l.clear(),r.clear();
for(int i = 1;i <= n;++i) cin >> a[i];
string s;
cin >> s;
for(int i = 0;i < n;++i) {
if(s[i] == 'B') l.push_back(a[i+1]);
else r.push_back(a[i+1]);
}
sort(l.begin(),l.end());
sort(r.begin(),r.end());
reverse(r.begin(),r.end());
bool si = true;
for(int i = 0;i < l.size();++i) {
if(l[i] < (i+1)) {
si = false;
break;
}
// cout << l[i] << endl;
// cout << "si" << si << endl;
}
for(int i = 0;i < r.size();++i) {
if(r[i] > (n-i)) {
si = false;
break;
}
// cout << "si" << si << endl;
}
if(si) cout << "YES" << endl;
else cout << "NO" << endl;
}
int main()
{
// in_out();
IO;
int t;
cin >> t;
while (t--)
{
solve();
}
}
题目大意
就是说给定了n*m个框,然后给出一个人行动的轨迹上下左右
问这个人初始状态在哪个点的时候,能够行动的数量最多
解题思路
我们就假定自己是那个人,我们有一个套完备的行走策略。
当我们想要通过这个策略在这个空间中行走最多次数时,我们应该在哪个地方。这其实很像一个贪心的思维。
我们假定他一直向左走,那么我们就就希望初始位置在最右边
当左右移动的最大位置差大于m的时候此时也正是我们无路可走的时候。
上下行走同理。
这样,我们就得出了行走的奥妙了
解题代码
#include<bits/stdc++.h>
using namespace std;
#define IO ios::sync_with_stdio(0),cin.tie(0)
void in_out()
{
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
}
void solve()
{
int n,m;
cin >> n >> m;
string s;
cin >> s;
int l = 0,r = 0,u = 0,d = 0;
pair<int,int> p;
p.first = p.second = 0;
for(int i = 0;i < s.length();++i) {
if(s[i] == 'L') {
p.first -= 1;
l = min(l,p.first);
}
else if(s[i] == 'R') {
p.first += 1;
r = max(r,p.first);
}
else if(s[i] == 'U') {
p.second += 1;
u = max(u,p.second);
}
else {
p.second -= 1;
d = min(d,p.second);
}
if(r-l >= m ) {
if(s[i] == 'L') l += 1;
else r -= 1;
break;
}
else if(u-d >= n) {
if(s[i] == 'U') u -= 1;
else d += 1;
break;
}
}
cout << n-(-1*d) << ' ' << -1*l+1 << endl;
}
int main()
{
// in_out();
IO;
int t;
cin >> t;
while(t--) {
solve();
}
return 0;
}
本次总结
第一题,签到
第二题,简单推理
第三题,抽象模拟
第四题,归纳总结,逆向思维
第五题,贪心思考,求解最佳
纵观本场题目,出题人想必十分善于观察细小甚微的东西,从小小的规律中探寻出一条大道真知。不得不说,我十分敬佩这一场比赛的出题人。在高速发展的当今社会,能够静下心来去观察一下细小的规律,并试图在其中寻找人们所认同的公理甚至说真理,这是值得我去学习的。
同时,这场比赛中我也学习到了,各种基础思维的组合使用。
总而言之,这一场比赛的参与是我的荣幸。