无限欢愉 深入推进 我沦陷在那片故地 我渴饮着 你的呼吸 却得不到 你的心
test33
要死了喵。好想锤爆 * * * * * * 喵。
要死了喵。好想锤爆 * * * * * * 喵。
要死了喵。好想锤爆 * * * * * * 喵。
5-A 骑行 (cycle.cpp)
先对 \(a\) 排序,考虑怎么贪心 \(b\),有一个一定贡献的点,对它贪心,发现答案相当于正反排序弄在一起喵。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=1000005;
int Type, n, a[N], b[N], Ans;
signed main() {
// freopen("1.txt","r",stdin);
freopen("cycle.in","r",stdin);
freopen("cycle.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> Type >> n;
up(i,1,n) cin >> a[i];
up(i,1,n) cin >> b[i];
sort(a+1,a+1+n);
sort(b+1,b+1+n);
if(Type==2) up(i,1,n/2) swap(b[i],b[n-i+1]);
up(i,1,n) Ans+=max(a[i],b[i]);
cout << Ans << '\n';
return 0;
}
5-B 游戏 (game.cpp)
先转转 \(a_i\in[0,m)\),然后 \(x\) 肯定是某个 \(a_i\) 你可以考虑数轴上两边的权如果相等那无所谓、如果不等一定会往一边走喵。
然后你枚举 \(x=a_1,\dots,a_n\),考虑 \(a_i-x\in(-m,m)\),你划分开来范围,是单调的,run 四个指针就好了喵。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
using namespace std;
const int N=200005, inf=1e18;
int T, n, m, v[N], A, B, C, D, Ans, s[N];
void mian() {
cin >> n >> m, A=B=C=D=0, Ans=inf;
up(i,1,n) cin >> v[i], v[i]=(v[i]%m+m)%m;
sort(v+1,v+1+n);
up(i,1,n) s[i]=s[i-1]+v[i];
up(u,1,n) {
int x=v[u];
while(A<n&&v[A+1]-x<-m/2) ++A;
while(B<n&&v[B+1]-x<=0) ++B;
while(C<n&&v[C+1]-x<=m/2) ++C;
while(D<n&&v[D+1]-x<m) ++D;
int val=0;
if(0<A) val+=(A-0)*(m-x)+(s[A]-s[0]);
if(A<B) val+=(B-A)*x-(s[B]-s[A]);
if(B<C) val+=(s[C]-s[B])-(C-B)*x;
if(C<D) val+=(D-C)*(m+x)-(s[D]-s[C]);
Ans=min(Ans,val);
}
cout << Ans << '\n';
}
signed main() {
// freopen("1.txt","r",stdin);
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while(T--) mian();
return 0;
}
5-C 序列 (seq.cpp)
按顺序插♂入,显然只关心三元组 \((i,j)\),然后要记一个对应的 \(\max\{w\}\),你肯定不能存下所有的状态喵,所以往支配点对那边去想喵,显然对于一个 \(j\) 只关心 \(i\) 不相等的最大/次大 \(w\),然后你好像不太关心很多个 \(j\) 来着,因为你的限制只有颜色 diff,你考虑排除一个相等的 \(j\),然后你还要额外两种 \(j\),所以三种 \(j\) 是极限了喵。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back
using namespace std;
const int N=200005;
int T, n, a[N], Ans;
struct node {
int l, r, v;
bool operator<(const node &rhs) const { return v<rhs.v; }
};
vector<node> sav;
void insert(node now) {
int cnt=0;
for(node &u:sav) {
if(u.r==now.r) ++cnt;
if(u.l==now.l&&u.r==now.r) {
u.v=max(u.v,now.v);
return;
}
}
if(cnt==2) {
for(node &u:sav) {
if(u.r!=now.r) continue;
if(now.v>u.v) swap(now,u);
}
}
else {
if(sav.size()==6) {
for(node &u:sav) {
if(now.v>u.v) swap(now,u);
}
}
else {
sav.pb(now);
}
}
}
void mian() {
cin >> n, Ans=0;
up(i,1,n) cin >> a[i];
sav.clear(), sav.pb((node){0,0,0});
up(o,1,n) {
int i=a[o];
node L=(node){0,i,1};
node R=(node){0,i,1};
for(node u:sav) {
if(u.l==i||u.r==i) continue;
if(u.v+1>L.v) {
if(u.r!=L.l) R=L;
L=(node){u.r,i,u.v+1};
}
else if(u.r!=L.l) {
if(u.v+1>R.v) R=(node){u.r,i,u.v+1};
}
}
Ans=max(Ans,L.v);
insert(L), insert(R);
}
cout << Ans << '\n';
}
signed main() {
// freopen("1.txt","r",stdin);
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while(T--) mian();
return 0;
}
5-D 城墙 (wall.cpp)
亲自尝试过直接上线段树计算 \(\sum_{h_u=a_u/b_u}\sum_{i=1}^n\min\{\max(h_{1\to i}),\max(h_{i\to n})\}\),被严格偏序、幂次讨论和常数创飞了。
首先你可以把墙高消掉,算水位线和是多少,墙高和显然是 \(2^{n-1}\sum(a_i+b_i)\)。
考虑计算 \(\sum_{H}\sum_{h_u=a_u/b_u}\sum_{i=1}^n[\max(h_{1\to i}\geq H,\max(h_{i\to n})\geq H)]\) 也就是差分成 01 序列,\(1\) 是大于等于的,设 \(cnt_i\) 表示 \(a_i/b_i\) 中 \(\geq H\) 的数量,\(counter_i\) 表示 \(cnt_u=i\) 的数量,题目变成了从大到小枚举 \(H\) 的间隔、修改 \(cnt\) 和 \(counter\),快速查询 \(\sum_{h_u=[a_u\geq H]/[b_u\geq H]}\sum_{i=1}^n[\exists l\leq i\leq r,h_l=h_r=1]\),不妨看看 \(i\) 的贡献更具体可以拆成什么 qwq
- 若 \(h_u=1\),一定贡献,系数 \(2^{n-1}\),当然藏了一个 \(\times cnt_i\) 喵。
这个直接用 \(counter\) 就能快速算了,贡献 \(2^{n-1}(2counter_2+counter_1)\)。
- 若 \(h_u=0\),要求存在 \(h_{l/r}=1\),设前/后 \(cnt_u=2/0\) 的数量为 \(x_l/x_r/z_l/z_r\),系数 \((2^{i-1}-[x_l=0]2^{z_l})(2^{n-i}-[x_r=0]2^{z_r})\),当然藏了一个 \(\times(2-cnt_i)\) 喵,我们考虑乘出来。
- \(\sum (2-cnt_i)2^{i-1}\times 2^{n-i}\)
改成 \(2^{n-1}(2counter_0+counter_1)\) 就行了喵。
- \(\sum(2-cnt_i)[x_l=0][x_r=0]2^{z_l+z_r}\)
首先 \(conter_2\neq 0\) 没有贡献,\(counter_2=0\) 的情况贡献 \(counter_0\times 2^{counter_0-1}\times 2+counter_1\times 2^{counter_1}=2^{counter_0}(counter_0+counter_1)\)。
- \(-\sum 2^{i-1}[x_r=0]2^{z_r}\times (2-cnt_i)\)
\(2^{i-1}(2-cnt_i)\) 看作单点上的权值,\([x_r=0]\) 看作增加前缀的乘法贡献,\(2^{z_r}\) 对每一个 \(cnt_u=0\) 看作撤销前缀乘法贡献,可以先全都加上去然后用逆元撤销,线段树容易维护。
- \(-\sum 2^{n-i}[x_l=0]2^{zl}\times (2-cnt_i)\)
同第三类,多开一颗线段树即可。
#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
using namespace std;
const int N=1000005, P=1e9+7, inv2=500000004;
int n, pw[N], a[N], b[N], ran[N], cnt[N], counter[3];
int Ans, sp[N], m;
inline int id(int i) { return i<=n?i:(i-n); }
inline int calc(int i) { return i<=n?a[i]:b[i-n]; }
inline void Mul(int &a,int b) { (a*=b)%=P; }
inline void Add(int &a,int b) { (a+=b)%=P; }
struct SGT {
int Type, tr[N<<2], mul[N<<2];
inline void tup(int p) {
tr[p]=(tr[ls(p)]+tr[rs(p)])%P;
}
inline void tdn(int p) {
Mul(mul[ls(p)],mul[p]), Mul(tr[ls(p)],mul[p]);
Mul(mul[rs(p)],mul[p]), Mul(tr[rs(p)],mul[p]);
mul[p]=1;
}
void build(int p=1,int s=1,int e=n) {
mul[p]=1;
if(s==e) { tr[p]=(2-cnt[s])*(Type?pw[n-s]:pw[s-1])%P; return; }
int mid=(s+e)>>1;
build(ls(p),s,mid), build(rs(p),mid+1,e);
tup(p);
}
void modify(int l,int r,int v,int p=1,int s=1,int e=n) {
if(l>r) return;
if(l<=s&&e<=r) {
Mul(mul[p],v), Mul(tr[p],v);
return;
}
tdn(p);
int mid=(s+e)>>1;
if(l<=mid) modify(l,r,v,ls(p),s,mid);
if(r>mid) modify(l,r,v,rs(p),mid+1,e);
tup(p);
}
void point(int x,int p=1,int s=1,int e=n) {
if(s==e) { tr[p]=mul[p]*(2-cnt[s])%P*(Type?pw[n-s]:pw[s-1])%P; return; }
tdn(p);
int mid=(s+e)>>1;
if(x<=mid) point(x,ls(p),s,mid);
if(x>mid) point(x,rs(p),mid+1,e);
tup(p);
}
} L, R;
signed main() {
// freopen("1.txt","r",stdin);
freopen("wall.in","r",stdin);
freopen("wall.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n, pw[0]=1;
up(i,1,n) pw[i]=2*pw[i-1]%P;
up(i,1,n) cin >> a[i], sp[++m]=a[i], ran[i]=i;
up(i,1,n) cin >> b[i], sp[++m]=b[i], ran[i+n]=i+n;
sort(sp+1,sp+1+m), m=unique(sp+1,sp+1+m)-sp-1;
sort(ran+1,ran+1+2*n,[](int i,int j){return calc(i)>calc(j);});
L.Type=0, L.build(), R.Type=1, R.build();
up(i,1,n) L.modify(1,i-1,2), R.modify(i+1,n,2), ++counter[0];
int j=1;
dn(i,m,1) {
while(j<=2*n&&calc(ran[j])>=sp[i]) {
int u=id(ran[j++]);
--counter[cnt[u]], ++cnt[u], ++counter[cnt[u]];
if(cnt[u]==1) L.modify(1,u-1,inv2), R.modify(u+1,n,inv2);
else L.modify(1,u-1,0), R.modify(u+1,n,0);
L.point(u), R.point(u);
}
int val=0;
Add(val,(2*counter[0]+counter[1])*pw[n-1]%P);
if(!counter[2]) Add(val,(counter[0]+counter[1])*pw[counter[0]]%P);
Add(val,-L.tr[1]), Add(val,-R.tr[1]);
Add(val,(counter[1]+2*counter[2])*pw[n-1]%P);
Add(Ans,(sp[i]-sp[i-1])%P*val%P);
}
up(i,1,n) Add(Ans,-(a[i]+b[i])%P*pw[n-1]%P);
cout << (Ans%P+P)%P << '\n';
return 0;
}

浙公网安备 33010602011771号