2022NOIP A层联测19
A. 皮胚
表示 分别匹配到 是否可行
转移就是简单分类讨论
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 2005;
char s[maxn], t[maxn];
bool f[maxn][maxn];
int n, m;
void solve(){
scanf("%s%s",s + 1, t + 1);
n = strlen(s + 1);
m = strlen(t + 1);
memset(f, 0, sizeof(f));
f[0][0] = 1;
for(int i = 0; i <= n; ++i)
for(int j = 0; j <= m; ++j)
if(f[i][j]){
if(t[j + 1] == '.')f[i + 1][j + 1] = 1;
if(t[j + 1] == s[i + 1])f[i + 1][j + 1] = 1;
if(t[j + 1] == '*'){
f[i][j + 1] = 1;
if(s[i + 1] == s[i])f[i + 1][j] = 1;
}
}
int ans = 0;
for(int i = 1; i <= n; ++i)ans += f[i][m];
printf("%d\n",ans);
}
int main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
int t; scanf("%d",&t);
for(int i = 1; i <= t; ++i)solve();
return 0;
}
B. 核冰
考场想的跟题解类似,对退位的维护不清楚具体怎么搞,而且好像很麻烦
这里使用了 巨佬的做法
考虑维护进位前的数,
如果 那么到第一个奇数/ 0 的一段 ,
退位可以直接逆操作,即到第一个偶数/1 的一段
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int read(){
int x = 0; char c = getchar(); bool f = 0;
while(!isdigit(c)){f = c == '-'; c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 500100, mx = 5e5 + 25;
int cnt[maxn], n, m, a[maxn];
int ans = 0;
struct seg{
struct node{
bool all0, all1;
int mi, tag;
}t[maxn << 2 | 1];
void push_up(int x){
int ls = x << 1, rs = x << 1 | 1;
t[x].all0 = t[ls].all0 & t[rs].all0;
t[x].all1 = t[ls].all1 & t[rs].all1;
t[x].mi = min(t[ls].mi, t[rs].mi);
}
void upd(int x, int w){
t[x].mi += w;
t[x].tag += w;
if(w & 1)swap(t[x].all0, t[x].all1);
}
void push_down(int x){
upd(x << 1, t[x].tag);
upd(x << 1 | 1, t[x].tag);
t[x].tag = 0;
}
void built(int x, int l, int r){
if(l == r){
t[x].mi = cnt[l];
t[x].all1 = cnt[l] & 1;
t[x].all0 = !(cnt[l] & 1);
return;
}
int mid = (l + r) >> 1;
built(x << 1, l, mid);
built(x << 1 | 1, mid + 1, r);
push_up(x);
}
int add(int x, int l, int r, int pos){
if(l >= pos){
if(t[x].all0 && t[x].mi)return upd(x, 1), r;
if(l == r){
if(!t[x].mi)t[x].mi = 1, t[x].all0 = false, t[x].all1 = true, ++ans;
else upd(x, 1);
return r - 1;
}
}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1, mr = 0;
if(pos <= mid)mr = add(x << 1, l, mid, pos);
if(pos > mid || mr == mid) mr = add(x << 1 | 1, mid + 1, r, pos);
push_up(x);
return mr;
}
int del(int x, int l, int r, int pos){
if(l >= pos){
if(t[x].all1 && t[x].mi > 1)return upd(x, -1), r;
if(l == r){
if(t[x].mi == 1)t[x].mi = 0, t[x].all0 = true, t[x].all1 = false, --ans;
else upd(x, -1);
return r - 1;
}
}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1, mr;
if(pos <= mid)mr = del(x << 1, l, mid, pos);
if(pos > mid || mr == mid) mr = del(x << 1 | 1, mid + 1, r, pos);
push_up(x);
return mr;
}
}t;
void change(){
int x = read(), y = read();
t.del(1, 1, mx, a[x]);
a[x] = y; t.add(1, 1, mx, a[x]);
}
int main(){
// freopen("merge.in","r",stdin);
// freopen("merge.out","w",stdout);
n = read(), m = read();
for(int i = 1; i <= n; ++i)++cnt[a[i] = read()];
for(int i = 1; i < mx; ++i){
cnt[i] += (cnt[i - 1] - 1) / 2;
ans += cnt[i] > 0;
}
t.built(1, 1, mx);
for(int i = 1; i <= m; ++i){
int op = read();
if(op & 1)change();
else printf("%d\n",ans);
}
return 0;
}
C. 方珍
二分答案,把 的 都看成
那么就可以双指针找出 的区间个数
那么这时就是
考虑按照 降序排序,每次尝试把答案 , 这样答案最多增加
复杂度就变成
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ull read(){
ull x = 0; char c = getchar();
while(!isdigit(c)){c = getchar();}
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 10005;
int n, k[maxn], w[maxn], m[maxn], a[maxn];
int p[maxn], nk, nm;
ull seed0[maxn], seed;
ull _rand(){
seed^=seed<<13;
seed^=seed>>7;
seed^=seed<<17;
return seed;
}
void read_test(){
for(int i=1; i<=n; ++i) a[i] = _rand() % nm;
}
int cnt[maxn];
bool check(int ans){
int now = 0, l = 1, ex = 0;
for(int i = 0; i <= nm + 1; ++i)cnt[i] = 0;
for(int r = 1; r <= n; ++r){
if(a[r] < ans)ex += cnt[a[r]] == 0, ++cnt[a[r]];
while(ex >= ans){
while(a[l] >= ans)++l;
--cnt[a[l]];
ex -= cnt[a[l]] == 0;
++l;
}
now += r - l + 1;
if(now >= nk)return false;
}
return now < nk;
}
bool cmp(int x, int y){return w[x] > w[y];}
int main(){
// freopen("mex.in","r",stdin);
// freopen("mex.out","w",stdout);
n = read();
for(int i = 1; i <= n; ++i)p[i] = i;
for(int i = 1; i <= n; ++i){ k[i] = read(); w[i] = read(); m[i] = read(); seed0[i] = read();}
sort(p + 1, p + n + 1, cmp);
int ans = w[p[1]];
for(int i = 1; i <= n; ++i){
int now = p[i];
if(ans >= min(n, m[now]) + w[now] + 1)continue;
nk = k[now]; nm = m[now]; seed = seed0[now];
read_test();
while(check(ans + 1 - w[now]))++ans;
}
printf("%d\n",ans);
return 0;
}
D. 术劣
一个结论, 等差数列打乱公差
那么对于一个区间,如果 就是合法的
变形成为
于是上线段树套路,移动 , 叶节点维护 区间信息
单调栈可以简单维护
考虑如何维护
每个位置的 最多变化 次,那么可以每次暴力修改
用并查集维护 相同的连续段,每次变化时把段内位置都单点修改即可
因为我们取的是后缀 所以集合的个数也是最多
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define int long long
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 200005;
int a[maxn], n;
struct seg{
struct node{
int tag, mi, cntmi;
}t[maxn << 2 | 1];
void push_up(int x){
t[x].mi = min(t[x << 1].mi, t[x << 1 | 1].mi);
t[x].cntmi = 0;
if(t[x].mi == t[x << 1].mi)t[x].cntmi += t[x << 1].cntmi;
if(t[x].mi == t[x << 1 | 1].mi)t[x].cntmi += t[x << 1 | 1].cntmi;
}
void push_down(int x){
int ls = x << 1, rs = x << 1 | 1;
t[ls].mi += t[x].tag;
t[ls].tag += t[x].tag;
t[rs].mi += t[x].tag;
t[rs].tag += t[x].tag;
t[x].tag = 0;
}
void built(int x, int l, int r){
if(l == r){
t[x].cntmi = 1;
return;
}
int mid = (l + r) >> 1;
built(x << 1, l, mid);
built(x << 1 | 1, mid + 1, r);
push_up(x);
}
void modify(int x, int l, int r, int L, int R, int val){
if(L <= l && r <= R){
t[x].mi += val;
t[x].tag += val;
return;
}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1;
if(L <= mid)modify(x << 1, l, mid, L, R, val);
if(R > mid)modify(x << 1 | 1, mid + 1, r, L, R, val);
push_up(x);
}
void modify_one(int x, int l, int r, int pos, int val){
if(l == r){
t[x].mi += val;
return;
}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1;
if(pos <= mid)modify_one(x << 1, l, mid, pos, val);
else modify_one(x << 1 | 1, mid + 1, r, pos, val);
push_up(x);
}
int query(int x, int l, int r, int L, int R, int val){
if(L <= l && r <= R){
assert(t[x].mi >= val);
return t[x].mi == val ? t[x].cntmi : 0;
}
if(t[x].tag)push_down(x);
int mid = (l + r) >> 1, ans = 0;
if(L <= mid)ans += query(x << 1, l, mid, L, R, val);
if(R > mid)ans += query(x << 1 | 1, mid + 1, r, L, R, val);
return ans;
}
}t;
int stmi[maxn], top1, stmx[maxn], top2;
int f[maxn], gg[maxn], l[maxn];
int fa(int x){return x == f[x] ? x : f[x] = fa(f[x]);}
void merge(int x, int y){
x = fa(x); y = fa(y);
if(x == y)return;
l[x] = min(l[x], l[y]);
f[y] = x;
}
ll ans = 0;
#undef int
int main(){
#define int long long
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
n = read(); for(int i = 1; i <= n; ++i)a[i] = read();
for(int i = 1; i <= n; ++i)f[i] = i, l[i] = i;
t.built(1, 1, n);
for(int r = 1; r <= n; ++r){
while(top1 && a[stmi[top1]] >= a[r]){
t.modify(1, 1, n, stmi[top1 - 1] + 1, stmi[top1], a[stmi[top1]] - a[r]);
--top1;
}
while(top2 && a[stmx[top2]] <= a[r]){
t.modify(1, 1, n, stmx[top2 - 1] + 1, stmx[top2], a[r] - a[stmx[top2]]);
--top2;
}
stmi[++top1] = r; stmx[++top2] = r;
if(r > 1){
int now = abs(a[r] - a[r - 1]);
gg[r - 1] = now; t.modify_one(1, 1, n, r - 1, now * (r - 1));
int las = r - 1;
for(int p = r - 2; p >= 1; --p){
p = fa(p);
now = __gcd(gg[p], now);
if(now != gg[p]){
for(int j = l[p]; j < las; ++j)t.modify_one(1, 1, n, j, j * now - j * gg[p]);
gg[p] = now;
}
if(gg[p] == gg[fa(las)])merge(p, las);
p = las = l[fa(p)];
}
}
++ans;
int las = r;
for(int p = r - 1; p >= 1; --p){
p = fa(p);
ans += t.query(1, 1, n, l[p], las - 1, gg[p] * r);
p = las = l[fa(p)];
}
printf("%lld ",ans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】