2021"MINIEYE杯"中超(5)补题
2021"MINIEYE杯"中超(5)
1004 Another String
维护这么一个数组:f[i, j]表示以i,j为起点的两个子序列可以满足条件的最大长度。那么当t在i ~ i + f[i, j]这个区间时,f[i, j]对答案是有贡献的。当t在j及以后时,f[i, j]对答案是没有贡献的。所以我们可以在求出f[i, j]后,维护一个差分矩阵。对于每个f[i, j],ans[i] ++ , ans[i + f[i,j]] -- ;这表示在这个范围内f[i, j]的贡献,同时当分割点大于等于j时是没有贡献的。所以我们还要有 ans[j] -= f[i, j],ans[j + 1] += f[i, j]来消除此部分的贡献。
最后取两次前缀和即可得到答案。
#include <bits/stdc++.h>
using namespace std;
const int N = 3010;
int t;
int f[N][N];//f[i][j]表示以i,j为起点的两个子序列满足条件的最大长度
int n, k;
char s[N];
int ans[N];
void solve()
{
cin >> n >> k;
cin >> (s + 1);
//尺取
for (int l = 2; l <= n; l ++ )//枚举右端点
{
int len = 0, dif = 0;//len为当前满足的最长区间长度,dif为当前不同的位置有多少个
for (int i = 1, j = l; j <= n; i ++ , j ++ )//从两个区间的起点开始扫两个子序列
{
while (dif <= k)//当满足条件的话继续往后移动
{
dif += (s[i + len] != s[j + len]);
len ++ ;
}
f[i][j] = min(len - 1, min(j - i, n - j + 1));//更新f[i][j]
len -- ;//后移一位
dif -= (s[j] != s[i]);
}
}
memset(ans, 0, sizeof ans);
//差分矩阵更新
for (int i = 1; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
{
ans[i] ++ ; ans[i + f[i][j]] -- ;
ans[j] -= f[i][j]; ans[j + 1] += f[i][j];
}
for (int i = 1; i <= n; i ++ ) ans[i] += ans[i - 1];
for (int i = 1; i <= n; i ++ ) ans[i] += ans[i - 1];
for (int i = 1; i < n; i ++ ) cout << ans[i] << endl;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin >> t;
while (t -- ) solve();
return 0;
}
1006 Cute Tree
模拟
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int t;
int n;
int a[N];
struct node
{
int a[3];
}tr[N << 2];
int cnt;
void build(int ro, int l, int r)
{
if (l == r) return;
if (r == l + 1)
{
build(tr[ro].a[0] = ++ cnt, l, l);
build(tr[ro].a[1] = ++ cnt, r, r);
}
else
{
int k = (r - l) / 3 + 1;
int b = l + k - 1;
int c = b + r >> 1;
build(tr[ro].a[0] = ++ cnt, l, b);
build(tr[ro].a[1] = ++ cnt, b + 1, c);
build(tr[ro].a[2] = ++ cnt, c + 1, r);
}
}
int main()
{
scanf("%d", &t);
while (t -- )
{
scanf("%d", &n);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
cnt = 1;
build(1, 1, n);
printf("%d\n", cnt);
}
return 0;
}
1007 Banzhuan
比赛时由于我的原因想错了最优情况,导致思路错误,没有过掉题。。。
最大情况:往第n层放满,然后让它掉下去,放n次。
最小情况:XOY,XOZ,YOZ层放满。
比较坑的地方就是取模操作,由于有除法,直接相除取模会导致错误,所以要用到逆元。我们可以快速幂求得逆元。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MOD = 1e9 + 7;
int t;
LL n;
LL qmi(LL a, LL k)//快速幂求逆元
{
LL res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % MOD;
k >>= 1;
a = (LL)a * a % MOD;
}
return res;
}
void solve()
{
cin >> n; n %= MOD;
LL a, b, c;
a = (n % MOD * n % MOD) * (n + 1) % MOD * (n + 1) % MOD * (2 * n + 1) % MOD * qmi(12,MOD - 2) % MOD;
b = (n - 1) % MOD * (n - 1) % MOD * (n + 2) % MOD * (n + 2) % MOD * qmi(4,MOD - 2) % MOD;
c = (n - 1) % MOD * n % MOD * (n + 1) % MOD * (n + 2) % MOD * (2 * n + 1) % MOD * qmi(12,MOD-2) % MOD - (n + 2) % MOD * (n - 1) % MOD * qmi(2,MOD - 2)%MOD;
LL r1 = ((a + b + c) % MOD + MOD) % MOD;
LL r2 = n * n % MOD * n % MOD * (n + 1) % MOD * (n + 1) % MOD * (2 * n + 1) % MOD * qmi(12, MOD - 2) % MOD * n % MOD;
cout << r1 << endl << r2 << endl;
}
int main()
{
cin >> t;
while (t -- ) solve();
return 0;
}