A Strange Table
有两个M x N的矩阵,一个逐行摆放,一个逐列拜访。给定一个数x,求x在逐列摆放的矩阵中的位置(i,j)在逐行摆放的矩阵中对应的数值
#include <cstdio>
using namespace std;
typedef long long ll;
int main()
{
int t;
cin >> t;
while (t--)
{
ll n, m, x;
cin >> n >> m >> x;
x--;
cout << x % n * m + x / n + 1 << endl;
}
return 0;
}
B Partial Replacement
有一个长度为 nn 的字符串只包含.和*
现在要求你把其中的第一个和最后一个必须变成x
其他的可以选择其中一些变成x
问最少需要把几个变成x使得相邻的两个x之间距离不超过 kk
将第一个和最后一个标记为l和r
如果l==r说明只有一个 则输出1;
否则, 从l+k开始到l找到第一个为*的点变化,并将l改为这个点
#include <iostream>
using namespace std;
const int maxn = 200;
typedef long long ll;
char a[maxn];
int main()
{
int t;
cin >> t;
while (t--)
{
int n, k;
cin >> n >> k;
cin >> a + 1;
int l, r;
for (int i = 1; i <= n; i++)
if (a[i] == '*')
{
l = i;
break;
}
for (int i = n; i >= 1; i--)
if (a[i] == '*')
{
r = i;
break;
}
int ans = 2;
if (l == r)
ans--;
while (r - l > k)
{
for (int i = k;; i--)
if (a[l + i] == '*')
{
l += i;
ans++;
break;
}
}
cout << ans << endl;
}
//system("pause");
}
C Double-ended Strings
给出两个字符串 a, ba,b 每次可以删掉 aa 或 bb 的第一个字符或最后一个字符,问最少删几个字符使得两个字符串相等 T \leq1 00T≤100 组测试数据
#include <bits/stdc++.h>
using namespace std;
const int maxn = 25;
int main()
{
int t;
cin >> t;
while (t--)
{
char a[maxn], b[maxn];
cin >> a >> b;
int maxx = -1;
for (int i = 0; i < strlen(a); i++)
for (int j = 0; j < strlen(b); j++)
{
int res = 0;
for (int k = 0; k < strlen(a) && k < strlen(b); k++)
{
if (a[k + i] == b[k + j])
res++;
else
break;
}
maxx = max(maxx, res);
}
cout << strlen(a) + strlen(b) - 2 * maxx << endl;
}
return 0;
}
D Epic Transformation
给出一个长度为 nn 整数序列 aa,每次可以任选两个不相同的数都删掉,问最少剩下几个数
如果最大的数量maxx不超过剩下数量的一半,即2maxx>n,那么答案只能为0(偶数个,恰好全部删除)或1(奇数个,恰好剩下一个)
如果超过剩下数量的一半,那么答案为maxx-(n-maxx),即2maxx-n
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
map<int, int> m;
int maxx = -1;
for (int i = 0; i < n; i++)
{
int x;
cin >> x;
maxx = max(maxx, ++m[x]);
}
if (2 * maxx >= n)
cout << 2 * maxx - n << endl;
else
cout << (n & 1 ? 1 : 0) << endl;
}
return 0;
}
E Restoring the Permutation
有一个长度为 n 的排列 p,现在给出排列 p 的前缀最大值序列,求字典序最小和最大的排列 p
设前缀最大值序列为a,当a[i]!=a[i-1] 的时候,显然a[i]必须大于a[i-1],则此时,必有p[i]==a[i](想一想,为什么)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
typedef long long LL;
const int N = 200010;
int n;
int a[N];
int main()
{
int t;
cin>>t;
while(t --)
{
scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
set<int> S;
for(int i = 1; i <= n; i ++) S.insert(i);
for(int i = 1; i <= n; i ++)
{
if(a[i] != a[i - 1])
{
printf("%d ", a[i]);
S.erase(a[i]);
}
else
{
auto it = S.begin();
printf("%d ", *it);
S.erase(it);
}
}
puts("");
for(int i = 1; i <= n; i ++) S.insert(i);
for(int i = 1; i <= n; i ++)
{
if(a[i] != a[i - 1])
{
printf("%d ", a[i]);
S.erase(a[i]);
}
else
{
auto it = S.lower_bound(a[i] + 1);
it --;
printf("%d ", *it);
S.erase(it);
}
}
puts("");
}
return 0;
}
F Triangular Paths
有一个 nn 行,第 i 行有 i 个元素的下三角矩阵
当 (i+j)%2=0 时 (i, j)(i,j) 有一条通往 (i + 1, j)(i+1,j) 的边,否则 (i, j)(i,j) 有一条通往 (i + 1, j + 1)(i+1,j+1) 的边
可以花费 11 的代价令某一个点的出边在抵达 (i + 1, j)(i+1,j) 和 (i + 1, j + 1)(i+1,j+1) 之间互换
现在给出一个 nn 个点的点集,求从(1, 1)(1,1)出发最少花费多少代价可以遍历到这些点
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 2e5 + 10;
pii p[maxn];
int main()
{
int t;
cin >> t;
while (t--)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> p[i].first;
for (int i = 1; i <= n; i++)
cin >> p[i].second;
p[0].first = p[0].second = 1;
sort(p + 1, p + n + 1);
int ans = 0;
for (int i = 1; i <= n; i++)
{
//如果dx-dy==0 则 只向右下走
//如果x+y偶数 ans+=dx;
int dx = p[i].first - p[i - 1].first, dy = p[i].second - p[i - 1].second;
int t = dx - dy;
if (!t)
{
ans += ((p[i].first + p[i].second) % 2 == 0) ? dx : 0;
}
//如果dx-dy!=0 则既有向下走 也有向右下走
//如果x+y为奇数,只能向右下走,向下走多少次 ans+多少;
else
{
if ((p[i - 1].first - p[i - 1].second) % 2 == 0)
{
ans += (t >> 1);
}
else
ans += (t + 1) >> 1;
}
}
cout << ans << endl;
}
//system("pause");
return 0;
}
G Maximize the Remaining String
给定一个字符串s,求一个字典序最大的字符串t;t和s具有相同的集合。
集合中元素从大到小枚举,如果满足题意(填入元素c后,剩下字符和剩下集合依然成立) 则填入元素c
主程序
int slen(string s)
{
sort(s.begin(), s.end());
return unique(s.begin(), s.end()) - s.begin();
}
void solve()
{
string s;
cin >> s;
//求s集合的大小
int m = slen(s);
string t;
//用字符串s初始化集合,从大到小排列。
set<char, greater<int>> used(s.begin(), s.end());
while (m > 0)
{
//每次枚举集合中最大的元素
for (auto c : used)
//如果符合条件,则将c放进t,并从集合中删除c
if (check(s, c) == m - 1)
{
t += c;
used.erase(c);
//从字符串s中删除c字符
s = Delete(s, c);
break;
}
m--;
}
cout << t;
}
条件判定
//检验字符c是否符合条件
int check(string s, char c)
{
string t;
bool flag = false;
//扫描字符串s
for (auto e : s)
//如果遇到字符c,则删去字符c(不copy到t中)
if (e == c)
flag = true;
//(把出现在c后的字符copy到t中)
else if (e != c && flag)
t += e;
return slen(t);
}
string Delete(string s, char c)
{
string t;
bool flag = false;
for (auto e : s)
if (e == c)
flag = true;
else if (e != c && flag)
t += e;
return t;
}
完整代码
#include <bits/stdc++.h>
using namespace std;
int slen(string s)
{
sort(s.begin(), s.end());
return unique(s.begin(), s.end()) - s.begin();
}
int check(string s, char c)
{
string t;
bool flag = false;
for (auto e : s)
if (e == c)
flag = true;
else if (e != c && flag)
t += e;
return slen(t);
}
string Delete(string s, char c)
{
string t;
bool flag = false;
for (auto e : s)
if (e == c)
flag = true;
else if (e != c && flag)
t += e;
return t;
}
void solve()
{
string s;
cin >> s;
int m = slen(s);
string t;
set<char, greater<int>> used(s.begin(), s.end());
while (m > 0)
{
for (auto c : used)
if (check(s, c) == m - 1)
{
t += c;
used.erase(c);
s = Delete(s, c);
break;
}
m--;
}
cout << t;
}
int main()
{
int t;
cin >> t;
while (t--)
{
solve();
}
system("pause");
}