2022年多校冲刺NOIP联训测试5
又双叒叕垫底,
A 旅行日记
判断一下即可?注意一下细节
code
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int x = 0; char c = getchar();
while(c > '9' || c < '0')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
const int maxn = 100005;
int d[maxn], h[maxn], n, m, mx;
int main(){
n = read(); m = read();
for(int i = 1; i <= m; ++i)d[i] = read(), h[i] = read();
mx = d[1] + h[1] - 1;
for(int i = 2; i <= m; ++i){
int dt = d[i] - d[i - 1];
int dh = h[i] - h[i - 1];
if(dh < 0) dh = -dh;
if(dh > dt){printf("IMPOSSIBLE\n");return 0;}
mx = max(mx, max(h[i], h[i - 1]) + (dt - dh) / 2);
}
mx = max(mx, h[m] + n - d[m]);
printf("%d\n",mx);
return 0;
}
B 运动
单调队列+双指针
\(ST\)表会\(MLE\)可恶。。
code
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 5000005, INF = 0x3f3f3f3f;
int n, a[maxn], k;
int q1[maxn],h1,t1;
int q2[maxn],h2,t2;
int main(){
scanf("%d%d",&k,&n);
for(int i = 1; i <= n; ++i)scanf("%d",&a[i]);
int ans = 1, r = 1; h1 = h2 = 1; a[0] = a[1];
for(int l = 1; l <= n; ++l){
while(q1[h1]<l && h1 <= t1)++h1; while(q2[h2]<l && h2 <= t2)++h2;
while(r <= n){
ll mx = -INF, mi = INF;
if(h1 <= t1)mx = a[q1[h1]];mx = max(mx,(ll)a[r]);
if(h2 <= t2)mi = a[q2[h2]];mi = min(mi,(ll)a[r]);
if(mx - mi > k)break;
while(h1 <= t1 && a[q1[t1]] < a[r])--t1; q1[++t1] = r;
while(h2 <= t2 && a[q2[t2]] > a[r])--t2; q2[++t2] = r;
++r;
}
ans = max(ans, r - l);
}
printf("%d\n",ans);
return 0;
}
C 回文
\(g[i][j]\)表示\(i - j\)是否为回文
\(ans[l][r]\)表示答案
直接\(DP\)即可
代码用了一点奇怪的预处理,但是好像是对的
code
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
inline int read(){
int x = 0; char c = getchar();
while(c > '9' || c < '0')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
const int maxn = 5005;
char s[maxn];
int n, ans[maxn][maxn],g[maxn][maxn];
int main(){
scanf("%s",s + 1);
n = strlen(s + 1);
for(int i = 1; i <= n; ++i)g[i][i] = g[i][i - 1] = 1;
for(int i = 2; i <= n; ++i)
for(int j = 1; j <= n - i + 1; ++j)
g[j][j + i - 1] = (g[j + 1][i + j - 2] && (s[j] == s[i + j - 1]));
for(int i = 1; i <= n; ++i)
for(int j = 1; j + i - 1 <= n; ++j)
ans[j][i + j - 1] = ans[j + 1][i + j - 1] + ans[j][i + j - 2] - ans[j + 1][i + j - 2] + g[j][i + j - 1];
int T = read();
for(int i = 1; i <= T; ++i){
int l = read(), r = read();
printf("%d\n",ans[l][r]);
}
return 0;
}
基因进化
我还没进化,,,,
upd 进化了
尽量使一侧的字典序尽可能小,前面确定后,其实是后面的串正着接在后面或者反着接在前面
通过二分 + \(hash\)求出\(lcp\)后判断两种哪个字典序较小,对不能翻转的串到后面能翻转处再处理
过程中正串维护正\(hash\),反串维护反\(hash\),保证复杂度
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<deque>
using namespace std;
#define int long long
const int maxn = 300005;
const int mod = 998244353;
const int base = 1e9 + 7;
inline int read(){
int x = 0; char c = getchar();
while(c > '9' || c < '0')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
int qpow(int x, int y){
int ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
return ans;
}
int s[maxn], n ,m, ans[maxn];
int base_pow[maxn], base_inv[maxn];
bool vis[maxn];
void pre(){
base_pow[0] = 1;
for(int i = 1; i < maxn; ++i)base_pow[i] = 1ll * base_pow[i - 1] * base % mod;
base_inv[0] = 1, base_inv[1] = qpow(base, mod - 2);
for(int i = 2; i < maxn; ++i)base_inv[i] = 1ll * base_inv[i - 1] * base_inv[1] % mod;
}
struct arr{
int a[maxn], b[maxn], h1[maxn], h2[maxn], la, lb, lla, llb;
void pre(){
for(int i = 1; i <= lla; ++i)a[i] = 0;
for(int i = 1; i <= lla; ++i)h1[i] = 0;
for(int i = 1; i <= llb; ++i)b[i] = 0;
for(int i = 1; i <= llb; ++i)h2[i] = 0;
la = lb = lla = llb = 0;
}
void add(int x){
a[++lla] = x; b[++llb] = x;
h1[lla] = (1ll * h1[lla - 1] * base + a[lla]) % mod;
h2[llb] = (1ll * base_pow[llb - 1] * b[llb] + h2[llb - 1]) % mod;
}
int get_hasha(int l, int r){if(l > r)return 0;else return (1ll * h1[r] - h1[l - 1] * base_pow[r - l + 1] % mod + mod ) % mod;}
int get_hashb(int l, int r){if(l > r)return 0;else return ((0ll + h2[r] - h2[l - 1] + mod) % mod * 1ll * base_inv[l - 1]) % mod;}
int get_hash(int pos, int len){
if(len <= pos)return get_hashb(pos - len + 1,pos);
return (1ll * get_hashb(1, pos) * base_pow[len - pos] % mod + get_hasha(1, len - pos)) % mod;
}
bool check(int len){
return get_hash(lb, len) == get_hash(llb, len);
}
int get(int pos,int len){
if(len <= pos)return b[pos - len + 1];
return a[len - pos];
}
void judge(int len){
int lcp, l = 0, r = len;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid))lcp = mid, l = mid + 1;
else r = mid - 1;
}
if(lcp == n || get(lb, lcp + 1) < get(llb, lcp + 1)){llb = lb; la = lla;}
else {lla = la; lb = llb;}
}
void print(){
int p = 0;
for(int i = lb; i; --i)ans[++p] = b[i];
for(int i = 1; i <= la; ++i)ans[++p] = a[i];
}
}a;
void solve(){
a.pre();
for(int i = 1; i <= n; ++i){
a.add(s[i]);
if(!vis[i])a.judge(i);
}
a.la = a.lla;
a.print();
}
void work(){
n = read(), m = read();
for(int i = 1; i <= n; ++i)s[i] = read();
for(int i = 1; i <= m; ++i)vis[read()] = 1;
solve();
int ot = 0, ns = 1;
for(int i = 1; i <= n; ++i){
ot = (ot + 1ll * ans[i] * ns % mod) % mod;
ns = 1ll * ns * 37 % mod;
}
printf("%lld\n",ot);
for(int i = 1; i <= n; ++i)vis[i] = 0;
}
signed main(){
pre(); int op = read();
for(int i = 1; i <= op; ++i)work();
return 0;
}