Codeforces Round #605(Div3)A~E
A. Three Friends
题意:
- 给三个数\(a,b,c\),对每一个数字可以进行一次操作,加一减一或者不变。
- 求三个数两两组合的差值绝对值的最小值。
思路:
- 先排个序。
- 假设排序后三个数从小到大是\(a,b,c\)。
- 那么他们的两两差就是\((c-b)+(c-a)+(b-a)=2c-2a\)。
- 为了让他们的\(2c-2a\)最小,那就缩小\(c\),增大\(a\)。
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int a[3];
for(int i = 0; i < 3; i++)
cin >> a[i];
sort(a, a+3);
if(a[0] < a[2]) a[0]++;
if(a[2] > a[0]) a[2]--;
cout << 2*(a[2]-a[0]) << endl;
}
int main()
{
int T; scanf("%d", &T);
while(T--) solve();
return 0;
}
B. Snow Walking Robot
题意:
- 给出一串指令,最后回到原点,除了起点之外同一个地方不能经过两次。
- 你可以删除指令集中的一些指令或重组这些指令,问最多能走多少步。
思路:
- 构造题。
- 首先可以发现,L和R,U和D之间是可以相互抵消的。
- 那么我们只需要从这两个数字中取min即可。
- 剩下的让他们绕一个正方形。
- 值得注意的是,如果上下或左右某一方没有的时候,另一边只能为1,因为一个格子不能走两次。
#include<bits/stdc++.h>
using namespace std;
void solve()
{
string str;
cin >> str;
int l, r, u, d;
l = r = u = d = 0;
for(auto x : str)
{
if(x == 'L') l++;
if(x == 'R') r++;
if(x == 'U') u++;
if(x == 'D') d++;
}
int num1 = min(l, r);
int num2 = min(u, d);
if(num1 == 0 || num2 == 0)
{
num1 = min(num1, 1);
num2 = min(num2, 1);
}
string ans = "";
for(int i = 1; i++ <= num1;)
ans += 'L';
for(int i = 1; i++ <= num2;)
ans += 'U';
for(int i = 1; i++ <= num1;)
ans += 'R';
for(int i = 1; i++ <= num2;)
ans += 'D';
cout << ans.size() << endl;
cout << ans << endl;
}
int main()
{
int T; scanf("%d", &T);
while(T--) solve();
return 0;
}
C. Yet Another Broken Keyboard
题意:
- 给你一个字符串,小明想要练习自己的打字速度,所以他打算输入所有的子串。
- 但是键盘坏了,有部分键不能使了,问在这种情况下,小明还能输入多少个子串。
思路:
- 对于一个字符串而言,他有\(\frac{n(n+1)}{2}\)个子串。
- 那么可以把原先的字符串拆解成可以用键盘输入的几个字符串,然后直接计算答案就行。
#include<bits/stdc++.h>
using namespace std;
int n, k;
int vis[30]; //可以用的键位
string str;
int main()
{
int n, k;
cin >> n >> k;
cin >> str;
for(int i = 1; i <= k; i++)
{
char c[2];
scanf("%s", c);
vis[c[0]-'a']++;
}
//有溢出风险, 记得开longlong
long long ans = 0;
for(int i = 0; i < n; i++)
{
if(vis[str[i]-'a']) //如果当前位置可以
{
long long num = 0; //统计连续的可以的串
for(int j = i; j < n; j++)
{
i = j;
if(vis[str[j]-'a']) num++;
else break;
}
ans += num*(num+1) / 2;
}
}
cout << ans << endl;
return 0;
}
D. Remove One Element
题意:
- 给你一个长度为n的序列a。
- 你可以最多从序列中删除一个数字,最终的序列长度为\(n-1\)或者\(n\)。
- 你需要找到最长的可能的严格上升的子序列(这个子序列是连续的)。
思路:
- 假如说没有删除一个数字的条件的话,这题应该怎么写?
- 设\(f(i)\)表示前\(i\)个数字中,最长的严格上升的子序列长度为多少。
- 那么有递推方程:
- \(if(a(i)>a(i-1))\ f(i)=f(i-1)+1,else\ f(i)=1\)。
- 现在要删除某个数字,让序列变长,假设说删除的是第\(i\)号位置上的数字,那么如果\(a(i+1)>a(i-1)\),就可以快速的计算出\(i-1\)前面有多少个连续的严格上升的数字,但是后面的就不是很好计算,是\(O(n)\)的。
- 所以设\(g(i)\)表示以第\(i\)个数字为开头,最多能有多长的合法子序列。
- 枚举删除位置,用\(f(i-1)+g(i+1)\)更新答案。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int n, a[maxn], ans;
int f[maxn], g[maxn];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
f[1] = ans = 1;
for(int i = 2; i <= n; i++)
{
f[i] = 1;
if(a[i] > a[i-1]) f[i] = f[i-1]+1;
ans = max(f[i], ans);
}
g[n] = 1;
for(int i = n-1; i >= 1; i--)
{
g[i] = 1;
if(a[i] < a[i+1]) g[i] = g[i+1]+1;
}
ans = max(ans, g[1]);
for(int i = 2; i <= n-1; i++)
if(a[i+1]>a[i-1])
ans = max(ans, f[i-1]+g[i+1]);
ans = max(ans, f[n]);
cout << ans << endl;
return 0;
}
E. Nearest Opposite Parity
题意:
- 有一个长度为n的序列a。
- 每一步你可以从第\(i\)个位置跳跃到第\(i-a_i\)或\(i+a_i\)。(当然\(1\leq i-a_i,i+a_i\leq n\))。
- 对于每一个\(i\),你想知道他到\(j\)的最小步数,其中\(a_i,a_j\)奇偶性不同。
思路:
- 每个点可以跳到另一个点,所以不妨把整张图看成有\(n\)个点,至多有\(2n\)条边的有向图。
- 首先根据输入的数据进行建图。如果一个点\(x\)可以到\(y\),那么就建立一条从\(y\)到\(x\)的边。
- 之后进行bfs。
- 先加入偶数点入队列,就相当于以偶数点为终点(因为是反向建图),去找最近的可以到他的奇数点,同时更新答案。
- 奇数点同理。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn], n;
int head[maxn], nex[maxn<<2], ver[maxn<<2], tot;
inline void add_edge(int x, int y){
ver[++tot] = y; nex[tot] = head[x]; head[x] = tot;
}
int path[maxn][3];
void bfs(int dir)
{
queue<int> q;
for(int i = 1; i <= n; i++)
{
if(a[i] % 2 == dir)
{
path[i][dir] = 0;
q.push(i);
} else {
path[i][dir] = -1;
}
}
while(q.size())
{
int x = q.front(); q.pop();
for(int i = head[x]; i; i = nex[i])
{
int y = ver[i];
if(path[y][dir] == -1)
{ //代表是从奇偶性不同的点转移过来的
path[y][dir] = path[x][dir]+1;
q.push(y);
}
}
}
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
{
if(i + a[i] <= n) add_edge(i+a[i], i);
if(i - a[i] >= 1) add_edge(i-a[i], i);
}
bfs(0); bfs(1);
for(int i = 1; i <= n; i++)
{
if(a[i] % 2) printf("%d ", path[i][0]);
else printf("%d ", path[i][1]);
}
return 0;
}
原文地址:https://www.cnblogs.com/zxytxdy/p/12245992.html
时间: 2024-10-08 13:39:22