Preface

一边打一边写作文打的像shit,T2失智严重特判错了233

Orz Div1 Rank2的foreverlastnig聚聚,顺便说一句显然Luogu的比赛质量比以往显著提高了啊

以下题目按难度顺序排序


P5587 打字练习

送分模拟题,注意行首退格的问题以及一个坑点:范文中也有退格

#include<cstdio>
#include<iostream>
#include<string>
#define RI register int
#define CI const int&
using namespace std;
const int N=10005;
string a[N],b[N],tp; int ca,cb,cur,pre[N*10],t,lim; bool vis[N*10];
inline void get_str(string& s)
{
s=""; char ch; while ((ch=getchar())!='\n') s+=ch;
}
inline void del(string& s)
{
RI i; string t=s; s=""; lim=t.size();
for (i=0;i<lim;++i) pre[i]=i-1,vis[i]=1;
for (i=0;i<lim;++i) if (t[i]=='<')
{
vis[i]=0; pre[i+1]=pre[i];
if (~pre[i]) vis[pre[i]]=0,pre[i+1]=pre[pre[i]];
}
for (i=0;i<lim;++i) if (vis[i]) s+=t[i];
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
while (get_str(tp),tp!="EOF") a[++ca]=tp;
while (get_str(tp),tp!="EOF") b[++cb]=tp;
RI i,j; for (i=1;i<=ca;++i) del(a[i]);
for (i=1;i<=cb;++i) del(b[i]);
for (i=1;i<=min(ca,cb);++i)
for (j=0,lim=min(a[i].size(),b[i].size());j<lim;++j)
cur+=a[i][j]==b[i][j]; scanf("%d",&t);
return printf("%d",(int)(1.0*cur/(1.0*t/60)+0.5)),0;
}

P5588 小猪佩奇爬树

分类讨论题。考虑我们对于每种颜色,如果有三个及以上的点的子树内是没有这种颜色的点的,那么显然这种颜色的答案就是\(0\)

否则若有两个的话就是两端点的子树\(size\)乘积

剩下的就是一些特殊的情况,比如所有点在从上而下的一条链上的,那么答案就是下面的点的\(size\)乘上\(顶上的点的n-\text{顶上的点的size}\)

还有只有一个点的以及没有点的都要单独讨论

#include<cstdio>
#include<cctype>
#define int long long
#define RI register int
#define CI const int&
#define Tp template <typename T>
using namespace std;
const int N=3000005;
struct edge
{
int to,nxt;
}e[N<<1]; int n,head[N],cnt,col[N],x,y,pnum[N],all[N],fir[N],size[N],plc[N],f[N],g[N],ct[N];
class FileInputOutput
{
private:
static const int S=1<<21;
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define pc(ch) (Ftop!=Fend?*Ftop++=ch:(fwrite(Fout,1,S,stdout),*(Ftop=Fout)++=ch))
char Fin[S],Fout[S],*A,*B,*Ftop,*Fend; int pt[25];
public:
FileInputOutput(void) { Ftop=Fout; Fend=Fout+S; }
Tp inline void read(T& x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
Tp inline void write(T x)
{
if (x<0) pc('-'),x=-x; RI ptop=0; while (pt[++ptop]=x%10,x/=10);
while (ptop) pc(pt[ptop--]+48); pc('\n');
}
inline void flush(void)
{
fwrite(Fout,1,Ftop-Fout,stdout);
}
#undef tc
#undef pc
}F;
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt;
e[++cnt]=(edge){x,head[y]}; head[y]=cnt;
}
#define to e[i].to
inline void DFS(CI now=1,CI fa=0)
{
int tp=++ct[col[now]],fir=0,flag=0; size[now]=1;
for (RI i=head[now];i;i=e[i].nxt) if (to!=fa)
{
int ltp=ct[col[now]]; DFS(to,now); f[col[now]]+=size[now]*size[to];
size[now]+=size[to]; if (ltp!=ct[col[now]]) ++flag,fir=to;
}
f[col[now]]+=size[now]*(n-size[now]);
if (flag+(tp!=1||ct[col[now]]!=all[col[now]])==1)
{
++pnum[col[now]];
if (pnum[col[now]]==1) g[col[now]]=size[now]; else
if (pnum[col[now]]==2) g[col[now]]*=fir?(n-size[fir]):size[now];
}
}
#undef to
signed main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i; for (F.read(n),i=1;i<=n;++i) F.read(col[i]),++all[col[i]];
for (i=1;i<n;++i) F.read(x),F.read(y),addedge(x,y);
for (DFS(),i=1;i<=n;++i)
{
if (!ct[i]) F.write(1LL*n*(n-1)/2LL); else if (ct[i]==1) F.write(f[i]);
else if (pnum[i]==2) F.write(g[i]); else F.write(0);
}
return F.flush(),0;
}

P5589 小猪佩奇玩游戏

首先记\(d(x)\)表示有多少个数在删除时会把\(x\)删掉,利用概率的可加性我们发现一个数的贡献就是\(\frac{1}{d(x)}\)

那么撇开暴力计算的过程,我们发现很多数的\(d(x)=1\),那么这就意味着我们只要找出所有的\(d(x)\not=1\)的数计算贡献即可

考虑直接暴力枚举\(i\),然后把\(d(i^k)+1\),用map存储答案即可

最后跑出来发现\(n\)以内的数目很少,因此直接爆枚就可以了

PS:这题有容斥的\(\log^2 n\)的做法,我太菜了所以不会

#include<cstdio>
#include<map>
#define RI register int
#define CI const int&
using namespace std;
typedef map <int,int>:: iterator MI;
const int N=1e9;
int t,n,num; double ans; map <int,int> ct;
int main()
{
RI i; long long cur; for (i=2;i*i<=N;++i)
for (cur=i*i;cur<=N;cur*=i) ++ct[cur];
for (scanf("%d",&t);t;--t)
{
scanf("%d",&n); num=n; ans=0;
for (MI it=ct.begin();it!=ct.end();++it)
if (it->first<=n) --num,ans+=1.0/(it->second+1); else break;
printf("%.6lf\n",ans+num);
}
return 0;
}

P5590 赛车游戏

(以下偷懒直接贴了在Luogu写的题解并稍作修改)

白天比赛的时候基本上都写出来了,结果判无用边的时候脑抽了一下挂了

然而我还以为是后面写跪了一直在魔调233

首先看到这题我们先日常考虑一些简单的情况,我们来分析一下:

若起点不可达终点则输出\(-1\)(题面里之前没加上,可TM坑死人了)

若存在一个点无法从起点到达或者是无法到达终点(比赛的时候脑抽写成了233)那么这个点就是无用的,可以把它删掉,那么所有与它相连的边都可以随便赋值

然后考虑将剩下的边再建成图,那么此时出现环的话环上一定不合法,因此也可以判掉

那么我们惊喜地发现现在剩下的图已经是个DAG了,并且从起点到每个点的所有路径长度都要相同,那我们按拓扑序逐步转移即可。接下来有两种做法:

第一种是我比赛的时候写的,比较诡异,正确性感觉是对的但是又证明不来

考虑先拓扑排序一遍,求出将边长视为\(1\)时从起点到每个点的路径长度区间范围\([l_i,r_i]\)

那么我们考虑化边权为点权,把每个点到它的路径总长作为点权\(val_i\),那么显然每个\(val_i\)的取值范围就是\([r_i,9\times l_i]\)

考虑\(1\)号点的点权可以定下为\(0\),那么对于接下来的每个点,如果它的前驱点\(j\)的点权为\(val_j\),那么它的取值区间应该对\([val_j+1,val_j+9]\)取交

那么我们得出每个点的取值区间后直接在里面随便取一个值即可(顺手取最小值),同时再判掉一些无解的情况

乍一看随便取可能会错,但是这里的后面的点权范围是在前面的路径情况下考虑过的结果,因此可以通过此题

#include<cstdio>
#include<vector>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
typedef vector <int>:: iterator VI;
const int N=2005,INF=1e9;
struct interval
{
int l,r;
inline interval(CI L=-INF,CI R=INF)
{
l=L; r=R;
}
friend inline interval operator & (const interval& A,const interval& B)
{
return interval(max(A.l,B.l),min(A.r,B.r));
}
inline void operator &=(const interval& ots)
{
*this=*this&ots;
}
}v[N]; int n,m,x[N],y[N],z[N],q[N],val[N];
bool f1[N],f2[N]; vector <int> pre[N];
struct Graph
{
struct edge
{
int to,nxt;
}e[N]; int head[N],cnt,deg[N];
inline void clear(void)
{
memset(head,0,n+1<<2); memset(deg,0,n+1<<2); cnt=0;
}
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt; ++deg[y];
}
#define to e[i].to
inline void BFS(CI st,bool *vis)
{
RI H=0,T=1; vis[q[1]=st]=1; while (H<T)
{
int now=q[++H]; for (RI i=head[now];i;i=e[i].nxt)
if (!vis[to]) vis[to]=1,q[++T]=to;
}
}
inline bool Top_Sort(void)
{
RI H=0,T=0,i; for (i=1;i<=n;++i) if (!deg[i]) q[++T]=i;
while (H<T)
{
int now=q[++H]; for (i=head[now];i;i=e[i].nxt)
if (pre[to].push_back(now),!--deg[to]) q[++T]=to;
}
return T==n;
}
#undef to
}A,B;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
scanf("%d%d",&x[i],&y[i]),A.addedge(x[i],y[i]),B.addedge(y[i],x[i]);
for (A.BFS(1,f1),B.BFS(n,f2),i=1;i<=m;++i) if (!f1[x[i]]||!f2[x[i]]) z[i]=1;
if (!f1[n]) return puts("-1"),0;
for (A.clear(),i=1;i<=m;++i) if (!z[i]) A.addedge(x[i],y[i]);
if (!A.Top_Sort()) return puts("-1"),0; for (v[1]=interval(0,0),i=2;i<=n;++i)
{
int mi=INF,mx=-INF; for (VI it=pre[q[i]].begin();it!=pre[q[i]].end();++it)
mi=min(mi,v[*it].l+1),mx=max(mx,v[*it].r+1); v[q[i]]=interval(mi,mx);
}
for (i=1;i<=n;++i) if (v[i]=interval(v[i].r,9*v[i].l),v[i].l>v[i].r)
return puts("-1"),0; for (i=2;i<=n;++i)
{
interval tp; for (VI it=pre[q[i]].begin();it!=pre[q[i]].end();++it)
tp&=interval(val[*it]+1,val[*it]+9); v[q[i]]&=tp;
if (v[q[i]].l>v[q[i]].r) return puts("-1"),0; val[q[i]]=v[q[i]].l;
}
for (i=1;i<=m;++i) if (!z[i]) z[i]=val[y[i]]-val[x[i]];
for (printf("%d %d\n",n,m),i=1;i<=m;++i) printf("%d %d %d\n",x[i],y[i],z[i]);
return 0;
}

当然还有另一种更简单正确性也有保证的做法,我们考虑直接顺推每个点的权值区间,那么此时这个点的取法就会影响到后面了,因此我们可以倒着再做一遍,这样就可以保证正确性

#include<cstdio>
#include<vector>
#include<cstring>
#define RI register int
#define CI const int&
using namespace std;
typedef vector <int>:: iterator VI;
const int N=2005,INF=1e9;
struct interval
{
int l,r;
inline interval(CI L=-INF,CI R=INF)
{
l=L; r=R;
}
friend inline interval operator & (const interval& A,const interval& B)
{
return interval(max(A.l,B.l),min(A.r,B.r));
}
inline void operator &=(const interval& ots)
{
*this=*this&ots;
}
}v[N]; int n,m,x[N],y[N],z[N],q[N],val[N];
bool f1[N],f2[N]; vector <int> pre[N];
struct Graph
{
struct edge
{
int to,nxt;
}e[N]; int head[N],cnt,deg[N];
inline void clear(void)
{
memset(head,0,n+1<<2); memset(deg,0,n+1<<2); cnt=0;
}
inline void addedge(CI x,CI y)
{
e[++cnt]=(edge){y,head[x]}; head[x]=cnt; ++deg[y];
}
#define to e[i].to
inline void BFS(CI st,bool *vis)
{
RI H=0,T=1; vis[q[1]=st]=1; while (H<T)
{
int now=q[++H]; for (RI i=head[now];i;i=e[i].nxt)
if (!vis[to]) vis[to]=1,q[++T]=to;
}
}
inline bool Top_Sort(void)
{
RI H=0,T=0,i; for (i=1;i<=n;++i) if (!deg[i]) q[++T]=i;
while (H<T)
{
int now=q[++H]; for (i=head[now];i;i=e[i].nxt)
if (pre[to].push_back(now),!--deg[to]) q[++T]=to;
}
return T==n;
}
#undef to
}A,B;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
scanf("%d%d",&x[i],&y[i]),A.addedge(x[i],y[i]),B.addedge(y[i],x[i]);
for (A.BFS(1,f1),B.BFS(n,f2),i=1;i<=m;++i) if (!f1[x[i]]||!f2[x[i]]) z[i]=1;
if (!f1[n]) return puts("-1"),0;
for (A.clear(),i=1;i<=m;++i) if (!z[i]) A.addedge(x[i],y[i]);
if (!A.Top_Sort()) return puts("-1"),0; v[1]=interval(0,0);
for (i=2;i<=n;++i) for (VI it=pre[q[i]].begin();it!=pre[q[i]].end();++it)
v[q[i]]&=interval(v[*it].l+1,v[*it].r+9);
for (i=n;i>1;--i) for (VI it=pre[q[i]].begin();it!=pre[q[i]].end();++it)
v[*it]&=interval(v[q[i]].l-9,v[q[i]].r-1);
for (i=1;i<=n;++i) if (v[i].l>v[i].r) return puts("-1"),0;
for (i=1;i<=m;++i) if (!z[i]) z[i]=v[y[i]].l-v[x[i]].l;
for (printf("%d %d\n",n,m),i=1;i<=m;++i) printf("%d %d %d\n",x[i],y[i],z[i]);
return 0;
}

PS1:LTL的做法(即第二种做法)被叉掉了233

PS2:这题正解好像是差分约束,我想了想还挺有道理


P5591 小猪佩奇学数学

因为被没带草稿本那粉笔在机房写了两黑板233

来吧让我们来推式子QAQ,首先第一步考虑把下取整拆了:

\[Ans=\sum_{i=0}^n C_n^i\times p^i\times \lfloor \frac{i}{k} \rfloor
\]

\[=\sum_{i=0}^n C_n^i\times p^i\times \frac{i-i\mod k}{k}
\]

\[=\frac{1}{k}\times(\sum_{i=0}^n C_n^i\times p^i\times i-\sum_{i=0}^n C_n^i\times p^i\times(i\mod k))
\]

考虑对于括号内的式子前后分别计算,首先是

\[\sum_{i=0}^n C_n^i\times p^i\times i
\]

有组合数有幂次考虑怎么化成二项式定理的形式,我们考虑用组合数吸收掉\(i\):

\[\sum_{i=0}^n C_n^i\times p^i\times i=\sum_{i=1}^n n\times C_{n-1}^{i-1}\times p^{i}
\]

\[=np\times\sum_{i=0}^{n-1} C_{n-1}^i\times p^i=np\times(p+1)^{n-1}
\]

好了上面是热身,然后考虑怎么搞后面那部分:

\[\sum_{i=0}^n C_n^i\times p^i\times(i\mod k)
\]

\(i\mod k\)显然很麻烦,我们考虑枚举\(d=i\mod k\),那么有\((i-d)\mod k=0\),代进去有:

\[\sum_{i=0}^n C_n^i\times p^i\times(i\mod k)
\]

\[=\sum_{d=0}^{k-1} d\times\sum_{i=0}^n C_n^i\times p^i[(i-d)\mod k=0]
\]

然后下一步就要用到单位根反演了,不会的可以看浅谈单位根反演,代进去有:

\[\sum_{d=0}^{k-1} d\times(\sum_{i=0}^n C_n^i\times p^i\times \frac{1}{k}\sum_{j=0}^{k-1}\frac{\omega_k^{ij}}{\omega_k^{dj}})
\]

\[=\frac{1}{k}\sum_{j=0}^{k-1}\sum_{d=0}^{k-1} \frac{d}{w_k^{dj}}\sum_{i=0}^n C_n^i\times(\omega_k^j\cdot p)^i
\]

\[=\frac{1}{k}\sum_{j=0}^{k-1} (\omega_k^j\cdot p+1)^n\times\sum_{d=0}^{k-1} d\times(w_k^{k-j})^d
\]

发现后面那个\(\sum_{d=0}^{k-1} d\times(w_k^{k-j})^d\)是做这题的关键,考虑怎么快速计算一个一般形式的问题:

\[S=\sum_{i=0}^{n-1} i\times r^i
\]

方法其实挺多的,这里我用的是扰动法(不知道的可以到 《具体数学》 上看下):

\[S=\sum_{i=0}^{n-1} i\times r^i
\]

\[=\sum_{i=0}^{n-1} (i+1)\times r^{i+1} -n\times r^n
\]

\[r\times\sum_{i=0}^{n-1} i\times r^i+r\times\sum_{i=0}^{n-1} r^i -n\times r^n
\]

前面那一项我们发现\(S\)又被我们凑出来了,而后面那一项可以用等比数列求和得到通式,则:

\[S=r\times S+r\times \frac{r^n-1}{1-r}-n\times r^n
\]

移项就得到\(S=\frac{n\times r^n}{r-1}-\frac{r^{n+1}-r}{(r-1)^2} (r\not=1)\)

然后想必大家也发现了这里没有考虑\(r=1\)的情况,而显然有:

\[S=\frac{n\times(n-1)}{2} (r=1)
\]

综上所述这题就被解决了,而且由于\(998244352=2^{23}\times 119\),因此在\(k\in\{2^{\omega}|0\le\omega\le 20\}\)时是存在单位根的

#include<cstdio>
#define RI register int
#define CI const int&
using namespace std;
const int N=1<<20|5,mod=998244353;
int n,p,k,g,w[N],ans,ret;
inline int quick_pow(int x,int p=mod-2,int mul=1)
{
for (;p;p>>=1,x=1LL*x*x%mod) if (p&1) mul=1LL*mul*x%mod; return mul;
}
inline void inc(int& x,CI y)
{
if ((x+=y)>=mod) x-=mod;
}
inline void dec(int& x,CI y)
{
if ((x-=y)<0) x+=mod;
}
inline int sub(CI x,CI y)
{
int t=x-y; return t<0?t+mod:t;
}
inline int S(CI r,CI n)
{
if (r==1) return 1LL*n*(n-1)%mod*quick_pow(2)%mod;
return sub(1LL*n*quick_pow(r,n)%mod*quick_pow(r-1)%mod,1LL*sub(quick_pow(r,n+1),r)*quick_pow(r-1,mod-3)%mod);
}
int main()
{
scanf("%d%d%d",&n,&p,&k); g=quick_pow(3,(mod-1)/k);
RI i; for (w[0]=i=1;i<=k;++i) w[i]=1LL*w[i-1]*g%mod;
for (ans=1LL*n*p%mod*quick_pow(p+1,n-1)%mod,i=0;i<k;++i)
inc(ret,1LL*quick_pow((1LL*w[i]*p%mod+1)%mod,n)*S(w[k-i],k)%mod);
dec(ans,1LL*quick_pow(k)*ret%mod);
return printf("%d",1LL*quick_pow(k)*ans%mod),0;
}

P5592 美德的讲坛

我太菜了,以下解法出自官方题解

首先考虑找出一个\(\omega\),满足\(2^{\omega}\le x<2^{\omega+1}\),然后我们把\(a_i\)按照\(\lfloor \frac{a_i}{2^{\omega}}\rfloor\)分组

那么首先我们发现每个组内部的两两的异或都是\(<x\)的

然后细细分析我们发现只有相邻的组之前才有可能产生\(<x\)的异或值,因此我们把这两组的点拿出来,问题变成:

现在有两组点,左边每个点有一个权值 \(a_i\),右边每个点有一个权值\(b_i\)。现在要在左右各选出一些点,使得两两异或和\(<x\)

考虑用最小割来解决,如果我们将源点向左边的点连流量\(1\)的边,右边的点向汇点连流量\(1\)的边,然后当\(a_i\operatorname{xor} b_j\ge x\)时,\(i\)向\(j\)连流量\(\infty\)的边

那么跑出这个图的最小割,我们发现这个割就是要删去一些数字与相应源汇点的边,然后使得剩下的数字两两异或都\(<x\)的方案

然后考虑从最小割等于最大流的角度入手,由于这里是匹配问题我们用模拟费用流的思想,同时由于涉及异或我们建立0/1Trie

我们发现这个图的最大流也就是保留 \(a_i\operatorname{xor} b_j\ge x\)的边时,该二分图的最大匹配。

考虑在Trie树上统计,令\(solve(a,b,dep)\)表示当Trie树上以\(x,y\)为根的子树之间进行匹配,两棵子树的最大深度均为\(dep\)

然后记\(a_0,a_1,b_0,b_1\)表示\(a/b\)的左/右子树,用\(|a|\)表示\(a\)的子树里的点数

我们分类讨论,当\(x\)在\(dep\)这一位为\(1\)时,就意味着只有\(a_0\)和\(b_1\),\(a_1\)和\(b_0\)可以匹配

此时答案就是\(solve(a_0,b_1,dep-1)+solve(a_1,b_0,dep-1)\)

当\(x\)在\(dep\)这一位为\(0\)时,那么\(a_0\)和\(b_1\),\(a_1\)和\(b_0\)一定可以匹配

  • \(|a_0|<|b_1|\)且\(|a_1|<|b_0|\)时,答案就是\(|a|\)
  • \(|a_0|>|b_1|\)且\(|a_1|>|b_0|\)时,答案就是\(|b|\)
  • \(|a_0|<|b_1|\)且\(|a_1|>|b_0|\)时,答案就是\(\min(solve(a_1,b_1,dep-1),|b_1|-|a_0|,|a_1|-|b_0|)+|a_0|+|b_0|\)
  • \(|a_0|>|b_1|\)且\(|a_1|<|b_0|\)时,答案就是\(\min(solve(a_0,b_0,dep-1),|b_0|-|a_1|,|a_0|-|b_1|)+|a_1|+|b_1|\)

然后注意讨论下\(a=b\)的情况以及\(x=0\)的情况即可

最后修改由于每次最多只有\(\log\)的节点被改动了,因此类似于记忆化搜索来解决

总复杂度\((n+q)\log^2 \max(a_i)\),足以通过此题

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
#define CL const LL&
using namespace std;
typedef long long LL;
const int N=100005,R=60;
int n,q,x,rt; LL a[N],s,y;
class Zero_One_Trie
{
private:
struct segment
{
int ch[2],size,ans;
}node[N*R<<2]; bool vis[N*R<<2]; int tot;
public:
inline Zero_One_Trie(void) { rt=tot=1; }
#define lc(x) node[x].ch[0]
#define rc(x) node[x].ch[1]
#define S(x) node[x].size
#define A(x) node[x].ans
inline void insert(int& now,CL val,CI dep=R-1)
{
if (!~dep) return; if (!now) now=++tot; vis[now]=0; ++S(now);
insert(node[now].ch[(val>>dep)&1LL],val,dep-1);
}
inline void remove(int& now,CL val,CI dep=R-1)
{
if (!~dep) return; vis[now]=0; --S(now);
remove(node[now].ch[(val>>dep)&1LL],val,dep-1);
}
inline int solve(CI x=rt,CI y=rt,CI dep=R-1)
{
if (!x||!y||!S(x)||!S(y)) return 0; if (!~dep) return x==y?(S(x)-(S(x)&1)):min(S(x),S(y));
if (vis[x]&&vis[y]) return A(x); vis[x]=vis[y]=1; int ret;
if ((s>>dep)&1LL)
{
if (x==y) ret=solve(lc(x),rc(x),dep-1);
else ret=solve(lc(x),rc(y),dep-1)+solve(rc(x),lc(y),dep-1);
} else
{
int ax=solve(lc(x),lc(y),dep-1),ay=solve(rc(x),rc(y),dep-1);
if (x==y) ret=min(S(lc(x))-ax,S(rc(x))-ay)+ax+ay; else
{
if ((S(lc(x))<=S(rc(y)))==(S(rc(x))<=S(lc(y)))) ret=min(S(x),S(y)); else
if (S(lc(x))<S(rc(y))) ret=min(ay,min(S(rc(y))-S(lc(x)),S(rc(x))-S(lc(y))))+S(lc(x))+S(lc(y));
else ret=min(ax,min(S(lc(y))-S(rc(x)),S(lc(x))-S(rc(y))))+S(rc(x))+S(rc(y));
}
}
return A(x)=A(y)=ret;
}
#undef lc
#undef rc
#undef S
#undef A
}Trie;
int main()
{
RI i; for (scanf("%d%d%lld",&n,&q,&s),i=1;i<=n;++i)
scanf("%lld",&a[i]),Trie.insert(rt,a[i]);
if (!s) { for (RI i=1;i<=q+1;++i) puts("1"); return 0; }
for (printf("%d\n",n-Trie.solve()),i=1;i<=q;++i)
scanf("%d%lld",&x,&y),Trie.remove(rt,a[x]),
Trie.insert(rt,a[x]=y),printf("%d\n",n-Trie.solve());
return 0;
}

Postscript

我发现现在我对一切都一无所知

【LGR-060】洛谷10月月赛 I div.1&div.2的更多相关文章

  1. 【LGR-054】洛谷10月月赛II

    [LGR-054]洛谷10月月赛II luogu 成功咕掉Codeforces Round #517的后果就是,我\(\mbox{T4}\)依旧没有写出来.\(\mbox{GG}\) . 浏览器 \( ...

  2. 洛谷10月月赛II题解

    [咻咻咻] (https://www.luogu.org/contestnew/show/11616) 令人窒息的洛谷月赛,即将参加NOIp的我竟然只会一道题(也可以说一道也不会),最终145的我只能 ...

  3. 洛谷10月月赛Round.3

    Rank11:260=60+100+100 P2409 Y的积木 题目背景 Y是个大建筑师,他总能用最简单的积木拼出最有创意的造型. 题目描述 Y手上有n盒积木,每个积木有个重量.现在他想从每盒积木中 ...

  4. 洛谷10月月赛Round.1| P3398 仓鼠找sugar[LCA]

    题目描述 小仓鼠的和他的基(mei)友(zi)sugar住在地下洞穴中,每个节点的编号为1~n.地下洞穴是一个树形结构.这一天小仓鼠打算从从他的卧室(a)到餐厅(b),而他的基友同时要从他的卧室(c) ...

  5. 洛谷10月月赛Round.1| P3400 仓鼠窝[单调栈]

    题目描述 萌萌哒的Created equal是一只小仓鼠,小仓鼠自然有仓鼠窝啦. 仓鼠窝是一个由n*m个格子组成的行数为n.列数为m的矩阵.小仓鼠现在想要知道,这个矩阵中有多少个子矩阵!(实际上就是有 ...

  6. 洛谷10月月赛Round.1| P3399 丝绸之路 [DP]

    题目背景 张骞于公元前138年曾历尽艰险出使过西域.加强了汉朝与西域各国的友好往来.从那以后,一队队骆驼商队在这漫长的商贸大道上行进,他们越过崇山峻岭,将中国的先进技术带向中亚.西亚和欧洲,将那里的香 ...

  7. 洛谷10月月赛R2·浴谷八连测R3题解

    早上打一半就回家了... T1傻逼题不说了...而且我的写法比题解要傻逼很多T T T2可以发现,我们强制最大值所在的块是以左上为边界的倒三角,然后旋转4次就可以遍历所有的情况.所以二分极差,把最大值 ...

  8. 洛谷 4933 洛谷10月月赛II T2 大师

    [题解] f[i][j]表示最后一个数为h[i],公差为j的等差数列的个数.n方枚举最后一个数和倒数第二个数转移即可.注意公差可能为负数,需要移动为正数再作为下标. #include<cstdi ...

  9. 洛谷 4932 洛谷10月月赛II T1 浏览器

    [题解] x xor y的结果在二进制下有奇数个1,等价于x与y在二进制下的1的个数之和为奇数,因为x xor y减少的1的个数一定是偶数(两个数这一位都为1,xor的结果为0,减少了2个1) 那么答 ...

随机推荐

  1. <Design> 359 346

    359. Logger Rate Limiter 用map搭建. class Logger { HashMap<String, Integer> map; /** Initialize y ...

  2. <Stack> (高频)394 ( 高频)224

    394. Decode String 四种情况: 1. 数字,把之前有的数字乘以10再加本数字 2. ' [ ', 入口, 把之前的数字压入栈中并num归零. 3. ' ] ' ,出口,归零.用dfs ...

  3. ArcGIS10.2配置PostgreSQL9.2标准教程

    ArcGIS 支持Oracle.DB2.PostgreSQL.SQLite关系型数据库升级为企业地理数据,Oracle太庞大,SQLite太小,DB2多在IBM上用,只有PostgreSQL最适合,它 ...

  4. Python连载50-贪婪匹配、XPath介绍

    一.贪婪和非贪婪 1.贪婪:尽可能多的匹配,(*)表示贪婪匹配 2.非贪婪:找到符合条件的最小内容即可,(?)表示非贪婪 3.正则默认使用贪婪匹配 import re title = u"& ...

  5. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 8-1

    18.6.5  获取数据 PDO的数据获取方法与其他数据库扩展非常类似,只要成功执行SELECT查询,都会有结果集对象生成.不管使用PDO对象中的query()方法,还是使用prepare()和exe ...

  6. 内核态发生非法地址访问是否会panic

    https://mp.weixin.qq.com/s?__biz=MzAwMDUwNDgxOA==&mid=2652663676&idx=1&sn=b18ab57322594e ...

  7. 史上最全的Java命名规范[转]

    每个公司都有不同的标准,目的是为了保持统一,减少沟通成本,提升团队研发效能.所以本文中是笔者结合阿里巴巴开发规范,以及工作中的见闻针对Java领域相关命名进行整理和总结,仅供参考. 一.Java中的命 ...

  8. git 清除远程仓库已经删除的本地分支 清除已经合并到master的本地分支

    在gitlab中执行deleted merged.也是可以在本地看到这些分支的 查看本地分支和追踪情况: git remote show origin 可以发现远程分支已被删除的分支,根据提示可以使用 ...

  9. solidity智能合约implicit conversion异常

    问题场景 在使用^0.5.10版本的solidity时,如果使用this关键字会出现以下问题. 代码: require(tokenContract.balanceOf(this) >= _num ...

  10. SpringCloud的入门学习之Netflix-eureka(Eureka的集群版搭建)

    1.Eureka单机版的话,可能会出现单点故障,所以要保障Eureka的高可用,那么可以进行搭建Eureka的集群版. 高可用的Eureka的注册中心,将注册中心服务部署到多台物理节点上,形成一个集群 ...