A题:String Similarity
题意:给定一个长为2n-1的01字符串S,要求你构造一个长为n的字符串,使得该字符串与 s[1..n], s[2..n+1], s[3..n+2], ..., s[n..2n−1].至少存在一位相等
Solution
观察到每个字符串都有s[n],因此只需要将字符串全部改为s[n]即可
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
int t; cin >> t;
while (t--)
{
int n; cin >> n;
string s; cin >> s;
s = ' ' + s;
for (int i = 1; i <= n; i++)
cout<<s[n];
cout << endl;
}
return 0;
}
B题:RPG Protagonist
题意:两个背包有不同容量,给出两种物品的数量,重量和价值,问最多能带走两种物品的最大数量总和
Solution
刚开始觉得是背包,想了很久但是数据范围太大了,后面看题解才知道。
枚举第一个背包买第一种物品的数量,则第一个背包买第二种物品的数量便已经固定,对于第二个背包(先使得第一个物品重量最小),由于只考虑数量最多,所以优先购买重量最小的,如果第一个卖完了,才购买第二个
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int v1, v2, n1, n2, w1, w2;
int num2, num3, num4;
int ans;
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
int t; cin >> t;
while (t--)
{
cin >> v1 >> v2 >> n1 >> n2 >> w1 >> w2;
ans = -9;
if (w1 > w2)swap(n1, n2), swap(w1, w2);
for (int i = 0; i <= n1; i++)
{
if (i * w1 > v1)break;
num2 = min(n2, (v1 - i * w1) / w2);
num3 = min(n1 - i, v2 / w1);
num4 = min(n2 - num2, (v2 - num3 * w1) / w2);
ans = max(ans, i + num2 + num3 + num4);
}
cout << ans << endl;
}
return 0;
}
C题:Binary String Reconstruction
C题难度低于B题,属于基本的模拟题
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
int t; cin >> t;
while (t--)
{
int p = 0;
string s; cin >> s;
int x; cin >> x;
s = ' ' + s;
string s1(s.size() - 1, '1');
s1 = ' ' + s1;
for (int i = 1; i < s.size(); i++)
{
if (i - x < 1 && i + x >= s.size() && s[i] == '1')
{
p = 1;
break;
}
if (s[i] == '0')
{
if (i - x >= 1)s1[i - x] = '0';
if (i + x < s.size())s1[i + x] = '0';
}
}
for (int i = 1; i < s.size(); i++)
{
if (s[i] == '1')
{
int k = 0;
if (i - x >= 1)
if (s1[i - x] == '1')k = 1;
if (i + x < s.size())
if (s1[i + x] == '1')k = 1;
if (!k)
{
p = 1;
break;
}
}
}
if (p)cout << -1 << endl;
else
{
for (int i = 1; i < s.size(); i++)cout << s1[i];
cout << endl;
}
}
return 0;
}
D题:Zigzags
题意:给出一个序列a,问序列a满足条件的四元组的数量
Solution
四元组枚举中间两个变量即可,每次枚举,由乘法原理可得出当前中间变量满足条件的四元组的数量为中间第一个变量左边等于中间第二个变量的值的数量*中间第二个变量右边等于中间第一个变量的值的数量,注意到数字大小很小,因此只需要开一个前缀数量数组记录即可,从左到右每次对每个位置的左边的所有值进行一次记录,右边的数量可由前缀相减得到
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
int num[3030][3030];
int a[3030];
int ans;
int n;
void cal(int x, int y)
{
ans += num[x - 1][a[y]] * (num[n][a[x]] - num[y][a[x]]);
}
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
int t; cin >> t;
while (t--)
{
cin >> n;
ans=0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
num[i][j] = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
for (int j = 1; j <= n; j++)
num[i][a[j]] = num[i - 1][a[j]];
num[i][a[i]]++;
}
for (int i = 2; i <= n - 2; i++)
for (int j = i + 1; j <= n - 1; j++)
cal(i, j);
cout << ans << endl;
}
return 0;
}
与该题类似,但解决办法却不一样的:Acwing 三元组
Solution
与之不同的是,每个数都很大,如果只是数字大但个数少,我们可以用unordered_map记录,但该题个数也很多,所以必须考虑新的方法。
由于我们只需要纪录中间变量的前一个和后一个变量的数量,我们可以分别从前,从后遍历一次,每一次用unorderded_map纪录每个数字的的数量,若出现中间变量(即可以整除k),此时的a[i]/k或者a[i]*k的数量就是其左变量或者右变量的数量,用两个数组l[],r[]记录即可,最后由乘法原理计算即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
int l[N], r[N];
int a[N];
signed main()
{
ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
int n, k; cin >> n >> k;
unordered_map<int, int>num;
unordered_map<int, int>num1;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] % k == 0)
l[i] = num[a[i] / k];
num[a[i]]++;
}
for (int i = n; i>=1; i--)
{
if (a[i] % k == 0)
r[i] = num1[a[i]*k];
num1[a[i]]++;
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
ans += (l[i] * r[i]);
}
cout << ans;
return 0;
}