多校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的问题,但常数稍大。
操作的贪心策略和只有一次赋值操作比较显然,就不说了。
记\(a_i\)表示进行赋值操作前/后时第\(i\)位数,\(ad_i\)为第\(i\)位加的数(jiashu),\(mul_i\)为第\(i\)位乘的数,\(M\)表示所有数的乘积,显然有\(M=\prod\limits_{i=1}^n(a_i+ad_i)\times mul_i\)。
考虑每种操作带来的贡献。
- 赋值操作:如果将\(a_i\leftarrow y\),赋值前\(M_1=\frac{M}{(a_i+ad_i)\times mul_i}\times (a_i+ad_i)\times mul_i\),赋值后\(M_2=\frac{M}{(a_i+ad_i)\times mul_i}\times (y+ad_i)\times mul_i\),有\(M_2-M_1=M\times\frac{y-a_i}{a_i+ad_i}\)。
- 加操作:等价于将\(ad_i\leftarrow ad_i+y\),加之前\(M_1=\frac{M}{(a_i+ad_i)\times mul_i}\times (a_i+ad_i)\times mul_i\),加之后\(M_2=\frac{M}{(a_i+ad_i)\times mul_i}\times (a_i+ad_i+y)\times mul_i\),有\(M_2-M_1=M\times\frac{y}{a_i+ad_i}\)。
- 乘操作,等价于将\(mul_i\leftarrow mul_i\times y\),乘之前\(M_1=\frac{M}{(a_i+ad_i)\times mul_i}\times (a_i+ad_i)\times mul_i\),乘之后\(M_2=\frac{M}{(a_i+ad_i)\times mul_i}\times (a_i+ad_i)\times mul_i\times y\),有\(M_2-M_1=M\times(y-1)\)。
发现\(M\)是无用的,不用管就行,只需要对于每一个\(i\),将其最大的\(y-1,\frac{y}{a_i+ad_i},\frac{y-a_i}{a_i+ad_i}\)加到set里,然后每次操作后,因为\(a_i\)和\(ad_i\)都可能会更改,将已经插入的删除再插入新的即可,double可能会有精度问题,因为可能分子很小分母很大,所以用一个分数类即可。
时间复杂度\(O(n\log n)\),常数较大。
点此查看代码
#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();
}
树
改不完啊……
字符串
发现将答案就是将\(s[l:r]\)中的字符按照\(t\)中的位置编号,求相邻逆序对数\(+1\)。
考虑如何求逆序对数,发现值域很小,考虑对值域做点什么。
设\(f_{k,i,j}\)表示线段树上\(k\)区间内以\(i,j\)为断点的个数,有\(f_{k,i,j}=f_{ls(k),i,j}+f_{rs(k),i,j}\),\(f_{k,r(ls(k)),l(rs(k))}+=1\)。
然后直接放在线段树上跑就行了,时间复杂度\(O(mk^2\log n)\)。
点此查看代码
#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
挂个万穗爷。我也想被万穗爷抱着睡
本文来自博客园,作者:CuFeO4,转载请注明原文链接:https://www.cnblogs.com/hzoi-Cu/p/18561492