2024/08/07
mx模拟赛
A.简单移动
题目描述
给两个长度相等的字符串 ,每次可以在 中任选一个字符并移到串的开头。求将 变成 的最小操作次数(无解输出 )。
输入格式
输入两行两个字符串。保证长度相等。
输出格式
输出一行一个正整数表示答案。
样例
样例 1 输入
BABACBACBA
BABCABCAAB
样例 1 输出
7
数据范围与提示
令 为 的长度。
对于 的数据, 。
。
只包含大写字母。
首先不难发现的是,只要字母出现次数对的上,我们必然有一种方法重排(就是假设全部重来,把所有字母都按顺序放到一个空字符串中)
什么样的字母不需要重排呢?
我们发现,我们每拿一个字符,就有一坨字符从前面掉到后面,那么我们就可以通过这个过程来省事
那么我们用双指针,对 B B B 的后缀和 A A A 的从后往前的子序列 进行最大匹配,就可以求出不用动的字符数
最后用长度一减就完成了
O ( n ) O(n) O(n)
Ac-code:
#include<bits/stdc++.h>
using namespace std;
string a,b;
int t[30];
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
freopen("move.in","r",stdin);
freopen("move.out","w",stdout);
cin>>a>>b;
if(a.size() != b.size()) {puts("-1");return 0;}
for(int i = 0;i<a.size();i++) t[a[i] - 'A']++;
for(int i = 0;i<b.size();i++) t[b[i] - 'A']--;
int len = a.size();
for(int i = 0;i<30;i++) if(t[i]) {puts("-1");return 0;}
int i = len - 1,j = len - 1,ans = 0;
for(;i >= 0 && j >= 0;i--)
if(a[i] == b[j])
j--,ans++;
cout<<len - ans;
return 0;
}
B.星天花雨
题目描述
小 N 家的花园可以被看做一个 的网格图,从上到下依次为第 行至第 行,从左到右分别为第 列至第 列。
现在小 N 要在花园的某些位置种上花,具体来说,可以用 来表示花园的第 行第 列处是否种有花, 表示这个位置没有种花, 则表示这个位置种有一朵花。
小 N 找出了两个长度分别为 和 的 序列 ,那么她会在花园的第 行第 列种一朵花,当且仅当 。即
在种完这些花之后,小 N 想要在她的花园中选出一个子矩形,使得这片子矩形中恰好种有 朵花。具体来说,设她选出的矩形的左上角是 ,右下角是 ,那么这个矩形需要满足:
-
;
-
恰好有 个位置 满足 ,且 。
她想知道有多少种这样的子矩形。由于这样的子矩形可能很多,你只需要输出答案对 取模的值即可。
输入格式
第一行三个整数 。
第二行 个正整数 。
第三行 个正整数 。
输出格式
输出一行一个整数表示符合条件的子矩形个数。
样例
样例 1 输入
3 4 4
0 1 1
1 1 0 1
样例 1 输出
6
样例 1 解释
小 N 的花园对应的 如下:
0000
1101
1101
合法的子矩形共有六种:
-
左上角为 ,右下角为 ;
-
左上角为 ,右下角为 ;
-
左上角为 ,右下角为 ;
-
左上角为 ,右下角为 ;
-
左上角为 ,右下角为 ;
-
左上角为 ,右下角为 。
样例 2
该样例符合测试点 的约束。
样例 3
该样例符合测试点 的约束。
样例 4
该样例符合测试点 的约束。
数据范围与提示
对于所有测试点, 。每个测试点的具体限制见下表:
测试点编号 | 特殊性质 | |||
---|---|---|---|---|
无 | ||||
A | ||||
无 | ||||
A | ||||
无 | ||||
A | ||||
无 | ||||
特殊性质 A: 。
这个奇怪的描述矩形的方式,一看就很奇怪,非常值得关注
这些 1 , 0 1,0 1,0 直接决定了一行,或一列的情况
我们再来考察 1 1 1 的分布
只有当 a l i n e , b c o l a_{line},b_{col} aline,bcol都是 1 1 1,这个位置才是 1 1 1
稍微画画图就知道,对于一个矩形有多少个 1 1 1,取决于 a a a 区间 1 1 1 的个数 × \times × b b b 区间 1 1 1 的个数
那么,我们只需要知道有多少 a , b a,b a,b 中 1 1 1 个数为 i i i 的区间数,相乘即可
那么,对于 A i × B j = k A_i \times B_j = k Ai×Bj=k, A i , B j ∈ Z A_i,B_j \in Z Ai,Bj∈Z,
我们可以处理出每一个含 1 1 1 个数的区间数量,放在桶里
O ( n 2 ) O(n^2) O(n2) 可以过 80 80 80 分的点
显然这个地方可以优化————直接针对可能成为答案的区间,并用 O ( n ϕ ( n ) ) O(n\phi(n)) O(nϕ(n)) 求出来
什么样的可以成为答案?显然是 k k k 的因子
那么我们直接试除法,把每一个因子记录下来
最后针对每一个因子,求包含这么多
1
1
1 的区间
(这里不知道写没写唐,我是出来每一个
1
1
1 的 前缀
0
0
0 个数 + 1、后缀
0
0
0 + 1,然后对区间
1
1
1 相乘)
#include<bits/stdc++.h>
using namespace std;
#define int long long
int rd() {
int x = 0, w = 1;
char ch = 0;
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (ch - '0');
ch = getchar();
}
return x * w;
}
void wt(int x) {
static int sta[35];
int f = 1;
if(x < 0) f = -1,x *= f;
int top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
if(f == -1) putchar('-');
while (top) putchar(sta[--top] + 48);
}
const int N = 1e5+5,mod = 998244353;
int fa[N],fb[N],p[N],top = -1,tp,nxt[N],lst[N];
signed main() {
freopen("rain.in","r",stdin);
freopen("rain.out","w",stdout);
int n = rd(),m = rd(),k = rd();
vector<int> a(n + 1),b(m + 1);
for(int i = 1;i<=n;i++) a[i] = rd();
for(int i = 1;i<=m;i++) b[i] = rd();
for(int i = 1;i * i <= k;i++) {
if(k % i == 0) {
int j = k / i;
p[++top] = i;
if(i ^ j) p[++top] = j;
}
}
for(int i = 1;i<=n;i++) {
int j = i + 1;
if(a[i]) nxt[++tp] = 1;
if(a[i] && !a[j]){
while(!a[j] && j <= n) j++;
nxt[tp] = j - i;
i = j - 1;
}
}
int T = 0;
for(int i = 1;i<=n;i++) {
int j = i - 1;
if(a[i]) lst[++T] = 1;
if(a[i] && !a[j]) {
while(!a[j] && j >= 1) j--;
lst[T] = i - j;
i = nxt[T] + i - 1;
}
}
for(int i = 0;i<= top;i++) {
for(int j = 1;j<=tp - p[i] + 1;j++) {
int w = j + p[i] - 1;
fa[i] = (fa[i] + lst[j] * nxt[w] % mod) % mod;
}
}
tp = 0;
for(int i = 1;i<=m;i++) {
int j = i + 1;
if(b[i]) nxt[++tp] = 1;
if(b[i] && !b[j]){
while(!b[j] && j <= m) j++;
nxt[tp] = j - i;
i = j - 1;
}
}
T = 0;
for(int i = 1;i<=m;i++) {
int j = i - 1;
if(b[i]) lst[++T] = 1;
if(b[i] && !b[j]) {
while(!b[j] && j >= 1) j--;
lst[T] = i - j;
i = nxt[T] + i - 1;
}
}
for(int i = 0;i<= top;i++) {
for(int j = 1;j<=tp - p[i] + 1;j++) {
int w = j + p[i] - 1;
fb[i] = (fb[i] + lst[j] * nxt[w] % mod) % mod;
}
}
int ans = 0;
for(int i = 0;i<=top;i += 2) {
if(i == top) ans = (ans + fa[i] * fb[i] % mod) % mod;
else {
ans = (ans + fa[i] * fb[i ^ 1] % mod) % mod;
ans = (ans + fa[i ^ 1] * fb[i] % mod) % mod;
}
}
wt(ans % mod);
return 0;
}