A. Three swimmers
A题fist掉了,一个特判没想到,如果x能整除y,那么我一到泳池就能见到他。
如果不是,我到了泳池后,他当前圈已经游了x%y的时间,要见到他还需y-x%y的时间。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll cau(ll x, ll y)
{
if(x % y == 0) return 0;
else
{
x = x % y;
return y - x;
}
}
int main()
{
int t;
ll p, a[3];
cin >> t;
while(t -- )
{
cin >> p >>a[0] >> a[1] >> a[2];
ll minn = cau(p, a[0]);
for(int i=1; i<=2; ++ i ) minn = min(minn, cau(p, a[i]));
cout << minn << endl;
}
}
B. Card Deck
因为权值时乘上
n
n
n^n
nn,我们把一摞牌从原数组的尾部拿出来按原先顺序放到新数组的顶部,每次我们拿出以当前值最大的牌为头的一摞牌放到新数组,再从原数组中拿以当前值最大的牌为头的一摞牌,循环。
比赛的时候想到把原数组逆序sort一下,开个结构体同时记录下值和下标,如果执行了取出一摞牌的操作,更新总牌数,用f来记录是否拿过牌,不用考虑第二大值在第一大值的后面,会自动跳过,比赛的时候没有想到记录是否拿过牌,导致牌的总数更新错误,快结束时才A掉。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int x;
int idx;
};
bool cmp(node a,node b){
return a.x > b.x;
}
int main()
{
int t, n;
node a[100005];
int b[100005], p[100005];
cin >> t;
while(t -- )
{
cin >> n;
memset(p, 0, sizeof(p));
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
for(int i=0; i<n; ++ i )
{
cin >> p[i];
a[i].x = p[i];
a[i].idx = i;
}
sort(a, a+n, cmp);
int num = n;
int k=0;
int i=0, j;
bool f=0;
while(i < n)
{
for(j=a[k++].idx; j<num; ++ j)
{
b[i ++ ] = p[j];
f = 1;
}
if (f) num = a[k-1].idx;
f = 0;
}
for(int i=0; i<n; i ++ ) cout << b[i] << ' ';
cout << endl;
}
}
我们可以从题干中发现牌的值是不重复的,最重要的是只会有n张牌,所以牌的值只会是从1到n的元素都出现一遍(题目的隐含条件真的很重要,以后一定要结合样例多想想)。所以我们只要开个桶存一下权值的下标就行了。
这里给ed赋初值为n + 1是为了减少特判。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 100010;
int p[N], vis[N];
int t, n;
int main()
{
scanf("%d", &t);
while (t -- )
{
scanf("%d", &n);
memset(p, 0, sizeof(p)), memset(vis, 0, sizeof(vis));
for (int i = 1; i <= n; i ++ )
{
scanf("%lld", &p[i]);
vis[p[i]] = i;
}
int ed = n + 1;
for (int i = n; i>=1; i -- )
{
for (int j = vis[i]; j <= ed - 1; j ++ )
{
printf("%d ", p[j]);
}
ed = min(ed, vis[i]);
}
puts("");
}
return 0;
}
C. Maximum width
有两个字符串找到一个字串,使它下标之差的最大值在所有找到的子序列中是最大的。很明显,我们用双指针分别正向,反向扫描字符串s,记录下t中的字符第一次和最后一次在s中出现的位置,相邻的减一下就是当前部分的最优解,最后再取最大值即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200010;
int n, m;
string s, t;
int main()
{
cin >> n >> m >> s >> t;
int lef[N], rig[N];
for (int i = 0, j = 0; i < n; i ++ )
{
if (t[j] == s[i]) lef[j ++ ] = i;
if (j >= m) break;
}
for (int i = n - 1, j = m - 1; i >= 0; i -- )
{
if (t[j] == s[i]) rig[j -- ] = i;
if (j < 0) break;
}
int maxx = 0;
for (int i = 0; i < m - 1; i ++ )
{
maxx = max(maxx, rig[i + 1] - lef[i]);
}
printf("%d\n", maxx);
}
D. Genius’s Gambit
呜呜,看题解都想了一个下午,弱弱
首先我们要判断x - y得到的z能否满足有k个1。
已知x和y拥有的0,1数量相等我们知道01这种形式加上1后个数不会发生改变。因此我们可以将y设成10…01…1的形式假设y为1000111。
1.z = 100, x = 1001011 k = 1 2.z = 1100,x = 1010011 k = 2 3.z = 11100,x = 1100011 k = 3 此时我们把这个1移到了最最左端。
4.z = 11110, x = 1100101, k = 4 5.z = 11111, x = 1100110,k = 5
观察可以发现 max(k) = a + b - 2,所以要满足k <= a + b - 2.a = 0或 b = 1的情况需要特判,此时k只能为0。
#include <bits/stdc++.h>
using namespace std;
int a, b, k;
const int N = 200020;
int x[N], y[N], z[N];
int main()
{
cin >> a >> b >> k;
if (a == 0 || b == 1)
{
if (k)
{
cout << "No" << endl;
return 0;
}
else cout << "Yes" << endl;
}
else if (a + b - 2 >= k) cout << "Yes" << endl;
else
{
cout << "No" << endl;
return 0;
}
memset(z, 0, sizeof(z));
x[a + b] = 1, y[a + b] = 1;
// 构造y
for (int i = 1; i < a + b; i ++ )
{
if (i <= b - 1) y[i] = 1;
else y[i] = 0;
x[i] = y[i];
}
//构造z
int st = b - 1, ed = a + b - 2;
for (int i = st; i <= ed && k; i ++, k -- ) z[i] = 1;
ed = b - 2;
while (k -- )
{
z[ed -- ] = 1;
}
// 构造x
for (int i = 1; i <= a + b; i ++ )
{
x[i] += z[i];
if (x[i] >= 2)
{
x[i + 1] += x[i] / 2;
x[i] %= 2;
}
}
// 输出
for (int i = a + b; i >= 1; i -- ) cout << x[i];
printf("\n");
for (int i = a + b; i >= 1; i -- ) cout << y[i];
printf("\n");
return 0;
}