多校A层冲刺NOIP2024模拟赛25

他怎么把贴吧封了啊啊啊啊……

签到题,bitset水过就行了。

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
// FILE *InFile = stdin,*OutFile = stdout;
FILE *InFile = freopen("a.in","r",stdin),*OutFile = freopen("a.out","w",stdout);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 1e4 + 10;
int n,m;char s[N];
bitset<N> e[N];
inline void solve(){
cin>>n>>m;
rep(test,1,m,1){
cin>>(s+1);
bitset<N> S,T;
rep(i,1,n,1){
if(s[i] == '1' || s[i] == '3') T.set(i);
if(s[i] == '2' || s[i] == '3') S.set(i);
}
rep(i,1,n,1){
if(s[i] == '1') e[i] ^= S;
if(s[i] == '2') e[i] ^= T;
if(s[i] == '3') e[i] ^= S|T;
}
}
ll ans = 0;
rep(i,1,n,1){
ans += e[i].count();
if(e[i][i]) ans--;
}
cout<<ans/2;
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
solve();
}

序列

所有正解都因为没有特判or精度炸掉了,只有我一个过的,乐。讲一个可能与正解不同的做法(因为赛后看那么多正解被疯狂hack不止,所以没看,如果一样的话请告诉我这个唐氏),没有什么特判与炸int/long long的问题,但常数稍大。

操作的贪心策略和只有一次赋值操作比较显然,就不说了。

ai表示进行赋值操作前/后时第i位数,adi为第i位加的数(jiashu),muli为第i位乘的数,M表示所有数的乘积,显然有M=i=1n(ai+adi)×muli

考虑每种操作带来的贡献。

  1. 赋值操作:如果将aiy,赋值前M1=M(ai+adi)×muli×(ai+adi)×muli,赋值后M2=M(ai+adi)×muli×(y+adi)×muli,有M2M1=M×yaiai+adi
  2. 加操作:等价于将adiadi+y,加之前M1=M(ai+adi)×muli×(ai+adi)×muli,加之后M2=M(ai+adi)×muli×(ai+adi+y)×muli,有M2M1=M×yai+adi
  3. 乘操作,等价于将mulimuli×y,乘之前M1=M(ai+adi)×muli×(ai+adi)×muli,乘之后M2=M(ai+adi)×muli×(ai+adi)×muli×y,有M2M1=M×(y1)

发现M是无用的,不用管就行,只需要对于每一个i,将其最大的y1,yai+adi,yaiai+adi加到set里,然后每次操作后,因为aiadi都可能会更改,将已经插入的删除再插入新的即可,double可能会有精度问题,因为可能分子很小分母很大,所以用一个分数类即可。

时间复杂度O(nlogn),常数较大。

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
// FILE *InFile = stdin,*OutFile = stdout;
FILE *InFile = freopen("b.in","r",stdin),*OutFile = freopen("b.out","w",stdout);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
#define pii pair<db,int>
constexpr int N = 1e5 + 10,mod = 1e9 + 7;
int n,m,a[N];ll ad[N],mul[N],fz[N];
struct Segment_Tree{
struct segment_tree{
int l,r,val;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define val(x) tree[x].val
}tree[N<<2];
inline void pushup(int k){val(k) = 1ll*val(k<<1)*val(k<<1|1)%mod;}
void build(int k,int l,int r){
l(k) = l,r(k) = r;
if(l == r) return val(k) = a[l],void();
int mid = (l + r) >> 1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
pushup(k);
}
void upd(int k,int pos,int val){
if(l(k) == r(k)) return val(k) = val,void();
int mid = (l(k) + r(k)) >> 1;
if(pos <= mid) upd(k<<1,pos,val);else upd(k<<1|1,pos,val);
pushup(k);
}
inline int qry(){return val(1);}
#undef val
#undef l
#undef r
}T;
priority_queue<int> op[N][4];
struct frac{
ll z,m;frac(){}
frac(ll Z,ll M){ll gcd = __gcd(Z,M);z = Z/gcd;m = M/gcd;}
friend bool operator <= (const frac &x,const int &y){return x.z <= y*x.m;}
bool operator == (const frac &x)const{return z == x.z && m == x.m;}
bool operator < (const frac &x) const{return z*x.m < x.z*m;}
};
struct node{
frac del;int p,flag;
node(frac D,int P,int F):del(D),p(P),flag(F){}
bool operator < (const node &x) const {if(del == x.del)if(p == x.p) return flag < x.flag;else return p < x.p;else return del < x.del;}
};
set<node> q;
inline void solve(){
cin>>n>>m;rep(i,1,n,1) cin>>a[i],fz[i] = a[i],mul[i] = 1,ad[i] = 0;T.build(1,1,n);
auto ins = [&](int opr,int x,int y){
if(opr == 1 && y <= a[x]) return;
if(opr == 3 && y == 1) return;
switch(opr){
case 1:if(op[x][1].empty()) op[x][1].emplace(y);else if(op[x][1].top() < y) op[x][1].pop(),op[x][1].emplace(y);break;
case 2:op[x][2].emplace(y);break;
case 3:op[x][3].emplace(y);break;
}
};
auto get = [&](int p){return (fz[p]+ad[p]%mod)*mul[p]%mod;};
auto Ins = [](int p){
if(op[p][1].size()) q.emplace(frac((op[p][1].top()-fz[p]),(fz[p]+ad[p])),p,1);
if(op[p][2].size()) q.emplace(frac(op[p][2].top(),(fz[p]+ad[p])),p,2).second;
if(op[p][3].size()) q.emplace(frac(op[p][3].top()-1,1),p,3);
};
rep(i,1,m,1){int op,x,y;cin>>op>>x>>y;ins(op,x,y);}
rep(i,1,n,1) Ins(i); cout<<T.qry()<<' ';
int now = m+1;
rep(test,1,m,1){
if(q.empty() || (*q.rbegin()).del < frac(0,1)){now = test;break;}
auto p = (*q.rbegin()).p;
auto d = (*q.rbegin()).del;
auto flag = (*q.rbegin()).flag;q.erase(--q.end());
if(flag == 1){
auto x = op[p][1].top();op[p][1].pop();
if(op[p][2].size()) q.erase(node(frac(op[p][2].top(),(fz[p]+ad[p])),p,2));
if(op[p][3].size()) q.erase(node(frac(op[p][3].top()-1,1),p,3));
fz[p] = x;T.upd(1,p,get(p));
}
else if(flag == 2){
auto x = op[p][2].top();op[p][2].pop();
if(op[p][1].size()) q.erase(node(frac((op[p][1].top()-fz[p]),(fz[p]+ad[p])),p,1));
if(op[p][3].size()) q.erase(node(frac(op[p][3].top()-1,1),p,3));
ad[p] += x;T.upd(1,p,get(p));
}
else{
auto x = op[p][3].top();op[p][3].pop();
if(op[p][1].size()) q.erase(node(frac((op[p][1].top()-fz[p]),(fz[p]+ad[p])),p,1));
if(op[p][2].size()) q.erase(node(frac(op[p][2].top(),(fz[p]+ad[p])),p,2));
mul[p] = mul[p]*x%mod;T.upd(1,p,get(p));
}
Ins(p);cout<<T.qry()<<' ';
}
rep(i,now,m,1) cout<<T.qry()<<' ';
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
solve();
}

改不完啊……

image

字符串

发现将答案就是将s[l:r]中的字符按照t中的位置编号,求相邻逆序对数+1

考虑如何求逆序对数,发现值域很小,考虑对值域做点什么。

fk,i,j表示线段树上k区间内以i,j为断点的个数,有fk,i,j=fls(k),i,j+frs(k),i,jfk,r(ls(k)),l(rs(k))+=1

然后直接放在线段树上跑就行了,时间复杂度O(mk2logn)

点此查看代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,s,t,p) for(int i = s;i <= t; i += p)
#define drep(i,s,t,p) for(int i = s;i >= t; i -= p)
#ifdef LOCAL
FILE *InFile = freopen("in.in","r",stdin),*OutFile = freopen("out.out","w",stdout);
#else
// FILE *InFile = stdin,*OutFile = stdout;
FILE *InFile = freopen("d.in","r",stdin),*OutFile = freopen("d.out","w",stdout);
#endif
using ll=long long;using ull=unsigned long long;
using db = double;using ldb = long double;
const int N = 2e5 + 10;
int n,m,k,a[N],b[N];char s[N],t[N];
struct Segment_Tree{
struct node{
array<array<int,10>,10> v;
int l,r;
node(){memset(v.data(),0,sizeof(v));}
inline void operator += (int val){
array<array<int,10>,10> res;
rep(i,0,k-1,1) rep(j,0,k-1,1) res[(i+val)%k][(j+val)%k] = v[i][j];
v = move(res);l = (l + val)%k,r = (r + val)%k;
}
inline friend node operator + (const node &x,const node &y){
node res;res.l = x.l,res.r = y.r;
rep(i,0,k-1,1) rep(j,0,k-1,1) res.v[i][j] = x.v[i][j] + y.v[i][j];
res.v[x.r][y.l]++;
return res;
}
};
struct segment_tree{
int l,r,lz;node val;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define lz(x) tree[x].lz
#define val(x) tree[x].val
}tree[N<<2];
inline void pushup(int k){val(k) = val(k<<1) + val(k<<1|1);}
inline void pushdown(int p){
if(!lz(p)) return;
int ls = p<<1,rs = p<<1|1;
val(ls) += lz(p);val(rs) += lz(p);
lz(ls) += lz(p);lz(rs) += lz(p);lz(p) = 0;
lz(ls) %= k,lz(rs) %= k;
}
void build(int k,int l,int r){
l(k) = l,r(k) = r,lz(k) = 0;
if(l == r) return val(k).l = val(k).r = a[l],void();
int mid = (l + r) >> 1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);
}
void upd(int p,int l,int r,int val){
if(l <= l(p) && r(p) <= r) return val(p) += val,lz(p) += val,lz(p) %= k,void();
int mid = (l(p) + r(p)) >> 1;pushdown(p);
if(l <= mid) upd(p<<1,l,r,val);
if(r > mid) upd(p<<1|1,l,r,val);
pushup(p);
}
node qry(int k,int l,int r){
if(l <= l(k) && r(k) <= r) return val(k);
int mid = (l(k) + r(k)) >> 1;pushdown(k);
if(r <= mid) return qry(k<<1,l,r);
if(l > mid) return qry(k<<1|1,l,r);
return qry(k<<1,l,r)+qry(k<<1|1,l,r);
}
}T;
inline void solve(){
auto change = [&](int *a,char *s,int len){rep(i,0,len,1) a[i] = s[i] - 'a';};
cin>>n>>m>>k>>(s+1);change(a+1,s+1,strlen(s+1));T.build(1,1,n);
rep(test,1,m,1){
int op,l,r,x;cin>>op>>l>>r;
if(op == 1) cin>>x,T.upd(1,l,r,x);
else{
cin>>t;auto res = T.qry(1,l,r).v;
change(b,t,k-1);
int ans = 0;
rep(i,0,k-1,1) rep(j,0,i,1) ans += res[b[i]][b[j]];
cout<<ans+1<<'\n';
}
}
}
signed main(){
cin.tie(nullptr)->sync_with_stdio(false);
solve();
}
p

挂个万穗爷。我也想被万穗爷抱着睡

image

posted @   CuFeO4  阅读(28)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示