牛客小白月赛83
-
总结&&吐槽:
这场B wa了13发,笑死人了,真的会有这么菜的人么,读错题目了。下次读b这种题的时候要更加细心一点。 -
D.小天的子序列
- 题目大意:给定一个字符串全部由小写字母组成,然后又若干次查询,问有多少个以字符x开头以字符y结尾,并且长度为k。
- 思路分析:发现只要找到了x和y,那么只要长度大于等于k,那么就只要组合一下就能出答案。所以问题就回到了:怎么样去维护字符串?我们想要知道的东西无非就是两个,一是有多少个x开头y结尾的长度大于等于k的子串。然后思考一下就会发现可以去维护一个:以x字符开头,以y字符结尾,并且长度为len的子串有多少个。发现维护这个东西要O(n^2)的复杂度,由于给定字符串长度很小,所以直接维护就行。
- 注意事项:写模板的时候注意要开ll。。。
- 代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
ll inv[501],fact[501];
ll res[26][26][501];
ll qpow(ll a,ll b) {
ll res = 1;
while(b) {
if(b&1) res = res*a%mod;
a = a*a%mod;
b >>= 1;
}
return res;
}
ll C(int n,int m) {
if(m > n) return 0;
return (fact[n]*inv[m]%mod*inv[n - m]%mod);
}
void init() {
inv[0] = 1,fact[0] = 1;
for(int i = 1; i <= 500; i++)
fact[i] = fact[i - 1]*i%mod;
inv[500] = qpow(fact[500],mod - 2);
for(int i = 499; i >= 1; i--)
inv[i] = inv[i + 1]*(i + 1)%mod;
}
int main() {
init();
//cout << C(5,2) << "\n";
int n;cin >> n;
string s;cin >> s;
s = " " + s;
for(int i = 1; i <= n; i++) {
for(int j = 1; j < i; j++) {
res[s[j] - 'a'][s[i] - 'a'][i - j + 1]++;
}
}
int q;
cin >> q;
while(q--) {
char x,y;
int len;
cin >> x >> y;
cin >> len;
ll ans = 0;
for(int i = len; i <= n; i++) {
ans += (res[x - 'a'][y - 'a'][i]%mod*C(i - 2,len - 2))%mod;
}
cout << ans%mod << "\n";
}
return 0;
}
- 题目大意:给定两种贪吃蛇的运动轨迹,贪吃蛇在一个充满字符的举证中运动。然后给定若干查询,要回答贪吃蛇最多能吃掉多少字符。询问用3种,一种是修改,另外两种分别对应两种运动轨迹并且给定起点。每次输出最多能吃掉多少字符。
- 思路分析:因为轨迹是固定的,所以可以直接把二维平面变成一维的线段。然后用set记录每个字母出现的位置。其实求最多的并不是一个求最值问题,而是找到给定起点之后第一个不是该字符的其他字符。由于总共只有26个字母,所以二分一下就可以知道距离当前起点最近的字符是哪个,做差就可以。如果当前字符后面没有别的字符,那么代表当前点到最后点都是可以吃掉的。
- 代码:
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
typedef long long ll;
typedef pair<int,int> PII;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
int n,m;
vector<char> a[N];
int calcr(int x,int y) {
int res = 0;
if(x%2 == 0) res += (x - 1)*m + (m - y + 1);
else res = (x - 1)*m + y;
//cout << res << "\n";
return res;
}
int calcc(int x,int y) {
int res = 0;
if(y&1) res += (y - 1)*n + x;
else res += (y - 1)*n + (n - x + 1);
return res;
}
void solve() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) {
char c;
cin >> c;
a[i].push_back(c);
}
}
set<int> pos1[1000],pos2[1000];
bool flag = 1;
int cnt = 1;
for(int i = 1; i <= n; i++) {
if(!flag) {
for(int j = m - 1; j >= 0; j--) {
pos1[a[i][j] - 'a'].insert(cnt++);
}
flag = 1;
} else {
for(int j = 0; j < m; j++) {
pos1[a[i][j] - 'a'].insert(cnt++);
}
flag = 0;
}
}
flag = 1,cnt = 1;
for(int j = 0; j < m; j++) {
if(flag) {
for(int i = 1; i <= n; i++) {
pos2[a[i][j] - 'a'].insert(cnt++);
}
flag = 0;
} else {
for(int i = n; i >= 1; i--) {
pos2[a[i][j] - 'a'].insert(cnt++);
}
flag = 1;
}
}
/*for(int i = 0; i <= 25; i++) {
if(!pos1[i].empty()) {
cout << "i = " << i << "\n";
for(auto j : pos1[i])
cout << j << " ";
cout << endl;
}
}*/
int q;
cin >> q;
while(q--) {
int op;
cin >> op;
if(op == 1) {
int x,y;
cin >> x >> y;
char c;cin >> c;
auto t1 = calcr(x,y),t2 = calcc(x,y);
//cout << t1 << " " << t2 << "\n";
char d = a[x][y - 1];
pos1[d - 'a'].erase(t1),pos1[c - 'a'].insert(t1);
pos2[d - 'a'].erase(t2),pos2[c - 'a'].insert(t2);
a[x][y - 1] = c;
} else if(op == 2) {
int x,y;
cin >> x >> y;
char d = a[x][y - 1];
int t1 = calcr(x,y);
//cout << t1 << "\n";
int minn = 1e8;
for(int i = 0; i <= 25; i++) {
if(i == (d - 'a')) continue;
if(pos1[i].lower_bound(t1) != pos1[i].end()) {
auto pos = *pos1[i].lower_bound(t1);
minn = min(minn,pos);
}
}
if(minn == 1e8) cout << n*m - t1 + 1 << "\n";
else cout << minn - t1 << "\n";
} else {
int x,y;
cin >> x >> y;
char d = a[x][y - 1];
int t1 = calcc(x,y);
int minn = 1e8;
for(int i = 0; i <= 25; i++) {
if(i == (d - 'a')) continue;
if(pos2[i].lower_bound(t1) != pos2[i].end()) {
auto pos = *pos2[i].lower_bound(t1);
minn = min(minn,pos);
}
}
if(minn == 1e8) cout << n*m - t1 + 1 << "\n";
else cout << minn - t1 << "\n";
}
}
}
int main() {
int t = 1;
//cin >> t;
while(t--) {
solve();
}
return 0;
}