20191012
A.
SB平衡树拆点题
常数巨大
Code
#pragma GCC optimize("-fdelete-null-pointer-checks,inline-functions-called-once,-funsafe-loop-optimizations,-fexpensive-optimizations,-foptimize-sibling-calls,-ftree-switch-conversion,-finline-small-functions,inline-small-functions,-frerun-cse-after-loop,-fhoist-adjacent-loads,-findirect-inlining,-freorder-functions,no-stack-protector,-fpartial-inlining,-fsched-interblock,-fcse-follow-jumps,-fcse-skip-blocks,-falign-functions,-fstrict-overflow,-fstrict-aliasing,-fschedule-insns2,-ftree-tail-merge,inline-functions,-fschedule-insns,-freorder-blocks,-fwhole-program,-funroll-loops,-fthread-jumps,-fcrossjumping,-fcaller-saves,-fdevirtualize,-falign-labels,-falign-loops,-falign-jumps,unroll-loops,-fsched-spec,-ffast-math,Ofast,inline,-fgcse,-fgcse-lm,-fipa-sra,-ftree-pre,-ftree-vrp,-fpeephole2",3)
#include<bits/stdc++.h>
#define L(p) t[p].son0
#define R(p) t[p].son1
using namespace std;
typedef long long D;
const int maxn=500003;
struct node{
int son0,son1,sz,tot,len;
bool z;
D sum,s,zs;
}t[maxn];
int cnt,root;
int new_node(int len){
t[++cnt]=(node){0,0,1,len,len,0,0,0};
return cnt;
}
void pushup(int p){
t[p].sz=t[L(p)].sz+t[R(p)].sz+1;
t[p].tot=t[L(p)].tot+t[R(p)].tot+t[p].len;
t[p].sum=t[L(p)].sum+t[R(p)].sum+t[p].s;
}
void solve1(int p){if(p)swap(L(p),R(p)),t[p].z^=1;}
void solve2(int p,D z){if(p)t[p].s+=z*t[p].len,t[p].sum+=z*t[p].tot,t[p].zs+=z;}
void pushdown(int p){
if(t[p].z){
solve1(L(p)),solve1(R(p));
t[p].z=0;
}
if(t[p].zs){
solve2(L(p),t[p].zs),solve2(R(p),t[p].zs);
t[p].zs=0;
}
}
void output(int p){
if(!p)return;
// pushdown(p);
output(L(p));
printf("p:%d son0:%d son1:%d sz:%d tot:%d len:%d sum:%lld s:%lld z:%d zs:%lld\n",p,t[p].son0,t[p].son1,t[p].sz,
t[p].tot,t[p].len,t[p].sum,t[p].s,t[p].z,t[p].zs);
output(R(p));
}
void O(int p=root){
printf("BEGINBEGINBEGIN root:%d\n",root);
output(p);
printf("ENDENDENDENDEND\n");
}
void splitsz(int p,int k,int &x,int &y){
if(p==0){x=y=0;return;}
pushdown(p);
if(t[L(p)].sz+1<=k){
x=p;
splitsz(R(p),k-t[L(p)].sz-1,R(p),y);
}
else{
y=p;
splitsz(L(p),k,x,L(p));
}
pushup(p);
}
void splittot(int p,int k,int &x,int &y){
if(p==0){x=y=0;return;}
pushdown(p);
if(t[L(p)].tot+t[p].len<=k){
x=p;
splittot(R(p),k-t[L(p)].tot-t[p].len,R(p),y);
}
else{
y=p;
splittot(L(p),k,x,L(p));
}
pushup(p);
}
void merge(int &p,int x,int y){
if(x==0||y==0){p=x+y;return;}
if(rand()%(t[x].sz+t[y].sz)<t[x].sz){
pushdown(x);
merge(R(x),R(x),y);
pushup(x);
p=x;
}
else{
pushdown(y);
merge(L(y),x,L(y));
pushup(y);
p=y;
}
}
void rev(int l,int r){
int x,y,z;
splittot(root,l-1,x,y);
splittot(y,r-l+1,y,z);
solve1(y);
merge(y,x,y);
merge(root,y,z);
}
void add(int l,int r,D k){
int x,y,z;
splittot(root,l-1,x,y);
splittot(y,r-l+1,y,z);
solve2(y,k);
merge(y,x,y);
merge(root,y,z);
}
D query(int l,int r){
int x,y,z;
splittot(root,l-1,x,y);
splittot(y,r-l+1,y,z);
D ret=t[y].sum;
merge(y,x,y);
merge(root,y,z);
return ret;
}
void splnode(int i){ //[l,r] -> [l,i-1], [i,r]
int x,p1,p2,z;
splittot(root,i-1,x,p1);
splitsz(p1,1,p1,z);
int l=t[x].tot+1,r=t[x].tot+t[p1].len;
if(i>l&&i<=r){
t[p1].len=i-l;
p2=new_node(r-i+1);
t[p2].s=t[p1].s/(r-l+1)*(r-i+1);
t[p1].s=t[p1].s/(r-l+1)*(i-l);
pushup(p1),pushup(p2);
merge(p1,p1,p2);
}
merge(x,x,p1);
merge(root,x,z);
}
int main(){
srand(19260817);
int n,Q,ty,mo;
D l,r,k,last=0;
scanf("%d%d%d",&n,&Q,&ty);
n++;
merge(root,root,new_node(n));
while(Q--){
scanf("%d%lld%lld",&mo,&l,&r);
if(ty)l^=last,r^=last;
splnode(l);
splnode(r+1);
if(mo==0){
scanf("%lld",&k);
if(ty)k^=last;
add(l,r,k);
}
if(mo==1){
rev(l,r);
}
if(mo==2){
printf("%lld\n",last=query(l,r));
}
}
return 0;
}
B.
考虑一个合法的集合 \(S\) 在 \(h\) 数组中一定是一个极长的非减子序列。
先拓扑排序(也可以不用)求出 \(h\) 数组,然后神奇dp。
具体方法:
设 \(v_i\) 表示一个极长子序列的贡献,那么答案 \(=\sum (v_i(sum-v_i))=sum*\sum v_i-\sum v_i^2\)
转移方程见代码
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1003,maxm=500003,mod=998244353;
int Plus(int x,int y){return (x+=y)>=mod?x-mod:x;}
int Minus(int x,int y){return Plus(x,mod-y);}
void PlusEqual(int &x,int y){if((x+=y)>=mod)x-=mod;}
int mul(long long x,int y){return x*y%mod;}
int qpow(int x,int y){
int ans=1;
while(y){
if(y&1)ans=mul(ans,x);
x=mul(x,x);
y>>=1;
}
return ans;
}
const int inv2=qpow(2,mod-2);
int n,m,a[maxn],h[maxn],deg[maxn],gr[maxn][maxn],pre[maxn][maxn],sum,dp[maxn],dp2[maxn],cnt[maxn],ans;
bool ok(int j,int i){
if(h[i]<h[j])return 0;
return pre[i-1][h[i]]-pre[j][h[i]]-pre[i-1][h[j]-1]+pre[j][h[j]-1]==0;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",a+i),sum+=a[i];
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
if(u>v)swap(u,v);
gr[u][v]=1,deg[v]++;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(!gr[i][j])gr[j][i]=1,deg[i]++;
}
gr[n+1][i]=1,deg[i]++;
h[i]=1001;
}
h[n+1]=1001;
queue<int> q;
q.push(n+1);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=1;i<=n;i++){
if(gr[u][i]){
h[i]=min(h[i],h[u]-1);
if(--deg[i]==0)q.push(i);
}
}
}
for(int i=1;i<=n;i++)pre[i][h[i]]++;
for(int i=1;i<=n+1;i++){
for(int j=1;j<=1001;j++){
pre[i][j]+=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1];
}
}
for(int i=1;i<=n;i++){
if(ok(0,i)){
dp[i]=a[i];
cnt[i]=1;
}
for(int j=1;j<i;j++){
if(ok(j,i)){
PlusEqual(dp2[i],mul(dp[i],Plus(dp[j],mul(cnt[j],a[i]))));
int tot=mul(mul(cnt[j],Minus(cnt[j],1)),inv2);
PlusEqual(dp2[i],Plus(dp2[j],Plus(mul(mul(Minus(cnt[j],1),dp[j]),a[i]),mul(tot,mul(a[i],a[i])))));
PlusEqual(dp[i],Plus(dp[j],mul(cnt[j],a[i])));
PlusEqual(cnt[i],cnt[j]);
}
}
if(ok(i,n+1)){
PlusEqual(ans,Minus(mul(dp[i],sum),Minus(mul(dp[i],dp[i]),mul(2,dp2[i]))));
}
}
printf("%d\n",ans);
return 0;
}
C.
重题
做不来