爆炸了QAQ

传送门

\(A\) \(Mas\)的童年

这题我怎么感觉好像做过……我记得那个时候还因为没有取\(min\)结果\(100\to 0\)……

因为是个异或我们肯定得按位考虑贡献了

把\(a\)做个前缀异或和,记为\(s_i\),那么就是要找到

\[\max_{j<i}\{s_j+(s_j\oplus s_i)\}
\]

我们假设\(s_i\)第\(k\)位为\(a\),\(s_j\)第\(k\)位为\(b\),\(s_j+(s_j\oplus s_i)\)第\(k\)位为\(c\)

然后分类讨论\(a,b\)的取值

\[a=1,b=0\to c=1
\]

\[a=1,b=1\to c=1
\]

\[a=0,b=1\to c=2
\]

\[a=0,b=0\to c=0
\]

那么我们显然可以按位贪心,如果\(s_i\)第\(k\)位为\(1\),那么\(s_j\)的第\(k\)位无论取\(1\)还是取\(0\)都没有关系。如果\(s_i\)第\(k\)位为\(0\),那么如果在满足之前的一堆限制的条件下(即之前可能有几位也需要强制取\(1\)),\(s_j\)的第\(k\)位取\(1\)的数仍然存在的话,那么肯定是取\(1\)最优。而且显然如果不取\(1\),后面怎么取都不会更优

所以有一个\(O(n^2)\)的做法,记一个\(vis_s\)表示是否存在\(s\)这几位全为\(1\)的数,然后处理完\(a_i\)之后暴力枚举子集,把对应的\(vis\)设为\(1\)就行了

所以我们成功优化到了和暴力相同的复杂度……

我们换个思路,记\(pos_s\)表示“满足\(s\)这几位全为\(1\)的数中,最小的位置是哪个”,那么每一次判断前面是否有某个数\(s\)这几位全为\(1\)的时候只要比较一下\(pos_s\)和\(i\)的大小就可以了。\(pos\)可以直接用类似高位前缀和的思路\(O(n\log n)\)搞出来

//minamoto
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
const int N=(1<<20)+5;
int a[N],pos[N],n,x,res;
int main(){
// freopen("testdata.in","r",stdin);
// freopen("testdata.out","w",stdout);
n=read();
fp(i,0,1048575)pos[i]=n+1;
fp(i,1,n)a[i]=read()^a[i-1],cmin(pos[a[i]],i);
fp(j,0,19)fd(i,1048575,0)if(i>>j&1)cmin(pos[i^(1<<j)],pos[i]);
fp(i,1,n){
x=0,res=0;
fd(j,19,0)if(a[i]>>j&1^1){
pos[x^(1<<j)]<=i?(x^=(1<<j),res+=(1<<(j+1))):0;
}else res+=(1<<j);
print(res);
}
return Ot(),0;
}

\(B\) \(Z\)的家乡

我永远讨厌数据结构题\(.jpg\)

如果我们记\(mx_u\)表示\(u\)这棵子树里最大的标号,那么\(u\)的子树\(v\)的遍历顺序就是按\(mx_v\)从大到小排序之后的顺序

我们可以记一个\(f_u\)表示\(u\)这个子树中遍历顺序的对应的值,那么\(f_u\)就是所有子树的\(f_v\)排序之后合并起来,再加上自己的值。如果每次暴力往上跳,随机数据下树高和儿子个数都是期望\(O(\log n)\)的,可以\(AC\)

然而这里数据并不随机

我们发现每一次加入点的过程都类似于\(LCT\)的\(access\),而且只有\(access\)时候虚边转为实边的那几个地方需要更新答案

由虚边转为实边,就是说这一棵子树的遍历顺序要到最前面

我们可以维护一个\(splay\),对于每一个在\(LCT\)上父亲边由实边转为虚边的点,把它们在\(splay\)上整个子树拆下来,然后重新插进去,插进去的时候使它们新的值最大

并不建议看代码理解因为我的代码已经丑到自己都看不下去了

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
R int res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R int x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+5,P=998244353,Base=257933,inv=612171754;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
int st[N],ss[N],bin[N],top,n;
struct LCT{
struct node{
node *ch[2],*fa;int sz,tag,id;
node(){}
inline void ppd(R int x){sz+=x,tag+=x;}
inline void pd(){if(tag)ch[0]->ppd(tag),ch[1]->ppd(tag),tag=0;}
inline bool is(){return fa->ch[0]!=this&&fa->ch[1]!=this;}
inline bool re(){return fa->ch[1]==this;}
void update(){if(!is())fa->update();pd();}
void rotate(){
node *y=fa,*z=y->fa;int d=re();
if(!y->is())z->ch[y->re()]=this;
fa=z,ch[d^1]->fa=y,y->ch[d]=ch[d^1],ch[d^1]=y,y->fa=this;
}
}pool[N],*p[N],*null;int num;
LCT(){null=&pool[num++],null->fa=null->ch[0]=null->ch[1]=null,null->sz=null->tag=null->id=0;}
inline node *newnode(){pool[num].fa=pool[num].ch[0]=pool[num].ch[1]=null;return &pool[num++];}
inline void Pre(R int n){fp(i,1,n)p[i]=newnode(),p[i]->id=i;}
//指针别xjb指!
//人工开个NULL!
void splay(node *x){
x->update();
for(R node *y=x->fa,*z=y->fa;!x->is();y=x->fa,z=y->fa){
if(!y->is())(x->re()^y->re())?x->rotate():y->rotate();
x->rotate();
}
}
void access(node *x){
node *t=null;
while(x!=null){
node *now=t;
while(now->ch[0]!=null)now->pd(),now=now->ch[0];
st[++top]=now->id,ss[top]=now->sz;
splay(x);
x->ch[1]=t,t->fa=x,t=x,x=x->fa;
}
++t->tag,++t->sz;
}
}A;
struct Splay{
struct node{
node *ch[2],*fa;int sz,res,id;
inline bool re(){return fa->ch[1]==this;}
inline bool is(){return fa->ch[0]!=this&&fa->ch[1]!=this;}
void upd(){
res=(ch[0]->res+1ll*id*bin[ch[0]->sz]+1ll*bin[ch[0]->sz+1]*ch[1]->res)%P;
sz=ch[0]->sz+ch[1]->sz+1;
}
void rotate(){
node *y=fa,*z=y->fa;int d=re();
if(!y->is())z->ch[y->re()]=this;
fa=z,ch[d^1]->fa=y,y->ch[d]=ch[d^1],ch[d^1]=y,y->fa=this,y->upd();
}
}pool[N],*null,*p[N],*S,*T,*rt;int num;
Splay(){null=&pool[num++],null->fa=null->ch[0]=null->ch[1]=null,null->sz=null->res=null->id=0;}
inline node *newnode(){pool[num].fa=pool[num].ch[0]=pool[num].ch[1]=null;return &pool[num++];}
void Pre(R int n){
fp(i,1,n)p[i]=newnode(),p[i]->id=i,p[i]->sz=1,p[i]->res=i;
S=newnode(),T=newnode(),rt=S,S->sz=T->sz=1;
S->ch[1]=T,T->fa=S,T->upd(),S->upd();
}
//指针别xjb指!
//人工开个NULL!
void splay(node *x,node *c){
if(c==null)rt=x;
for(R node *y=x->fa;x->fa!=c;y=x->fa){
if(y->fa!=c)(x->re()^y->re())?x->rotate():y->rotate();
x->rotate();
}
x->upd();
}
node *get(int x){
node *now=rt;
while(now!=null){
int sz=now->ch[0]->sz+1;
if(sz==x)return now;
else if(sz>x)now=now->ch[0];
else now=now->ch[1],x-=sz;
}
}
int rk(int x){
splay(p[x],null);
return p[x]->ch[0]->sz+1;
}
void insert(node *x,int k){
node *t1=get(k+1),*t2=get(k+2);
splay(t1,null),splay(t2,t1);
t2->upd(),t1->upd();
t2->ch[0]=x,x->fa=t2,t2->upd(),t1->upd();
}
inline int calc(){return mul(rt->res,inv);}
void solve(){
fd(i,top,3){
int tr=rk(st[i]),tl=tr-ss[i];
node *cl=get(tl),*cr=get(tr+1);
splay(cl,null),splay(cr,cl);
node *tmp=cr->ch[0];
tmp->fa=cr->ch[0]=null;
cr->upd(),cl->upd(),insert(tmp,0);
}
}
}B;
int x;
int main(){
// freopen("testdata.in","r",stdin);
n=read(),bin[0]=1;
fp(i,1,n+2)bin[i]=mul(bin[i-1],Base);
A.Pre(n),B.Pre(n),B.insert(B.p[1],0);
fp(i,2,n){
top=0,x=read(),A.p[i]->fa=A.p[x],A.access(A.p[i]);
B.solve();
B.insert(B.p[i],0);
print(B.calc());
}
return Ot(),0;
}

\(C\) 战棋游戏

做一道题学一大堆的经历不管什么时候都是很有趣的呢……

前置芝士

环的染色方案数

我们现在要对一个环进行染色,要求两两颜色不同,设点的个数为\(n\),颜色个数为\(c\),求方案数

设\(f_i\)表示\(i\)个点的染色方案数。我们可以钦定一个开头,设为\(1\),并顺时针一次记为\(2,3,...,n\)

如果\(1\)号点和\(n-1\)号点颜色不同,那么方案数为\(f_{n-1},\)\(n\)号点可以选的方案数就是\((c-2)\)

如果\(1\)号点和\(n-1\)号点颜色相同,那么方案数为\(f_{n-2}\),即等价于\(n-2\)个点的环再插一个进去,此时\(n\)号点的颜色方案数为\(c-1\)

所以我们可以求得递推公式

\[f_n=(c-2)f_{n-1}+(c-1)f_{n-2}
\]

初值为\(f_0=1,f_1=c\)

根据数列的特征方程(因为我数学课老师讲这个的时候我快睡着了所以我也不是很清楚所以具体百度),我们可以求得\(f_n\)的通项公式为

\[f_n=(c-1)^n+(-1)^n(c-1)
\]

如果强制环的两个端点相同的话,方案显然就是\(f_{n-1}\)

\(O(n^2)\)多项式\(Ln\)和多项式\(Exp\)

其实这里是可以\(O(n\log n)\)搞的然而代码实在太长而,且这里数据范围够小所以我们可以\(O(n^2)\)做,如果您耐心够好而且对自己的多项式码力有自信完全可以跳过这一节

经过\(shadowice\)巨巨一个下午的调教我终于会了

对于多项式\(Ln\),我们需要暴力的就是它求逆的过程,即我们需要暴力计算一个形如

\[F(x)={P(x)\over Q(x)}
\]

的柿子

根据\(Ln\)的使用条件,得有\([x^0]Q(x)=1\)

我们令\(T(x)=Q(x)-1\),则\(Q(x)=T(x)+1\),即

\[F(x)={P(x)\over T(x)+1}
\]

\[F(x)(T(x)+1)=P(x)
\]

\[F(x)=P(x)-F(x)T(x)
\]

因为有\([x^0]T(x)=0\),所以我们就可以直接暴力卷积把\(F(x)\)给一项一项卷出来了,卷完之后积分一下就可以求出\(Ln\)了

然后是多项式\(Exp\),即要求

\[F(z)=e^{G(z)}
\]

\[F'(z)=G'(z)F(z)
\]

没了

题解

我们很明显可以以骑士为关键点拆成若干部分,那么不同部分之间就是条链,影响方案数的只有两个端点颜色是否相同了

ps:我们代码里预处理的方案数没有算上两个端点的方案,所以两端相同的方案要除以\(c\),两端不同的方案要除以\(c(c-1)\)

我们\(2^k\)爆搜集合,表示强制\(s\)中的所有点为相同颜色,看看是否合法,如果合法的话记录总的贡献(即每一个点到它对应的下一个点的那条链上的方案数)

然后我们集合并卷积一下,求出\(f_{s,i}\)表示只允许\(s\)这个集合中有相同的颜色,且钦定的颜色相同的点的个数为\(i\)的总贡献

我们把\(f_s\)看成一个多项式,那么\({f_{s}}^c\)就代表选\(c\)种颜色的方案数,它的第\(k\)项就是总的方案

然而显然这样会算上一些不合法的情况,所以我们还得对\(s\)进行一个容斥

代码全是抄\(std\)的,因为这代码实在是太难写了我根本写不下去……

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
const int N=25,M=(1<<20)+5,P=1e9+7;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R ll x,R ll y){
R int res=1;x%=P;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
int sz[M],f[M][N],same[N],diff[N],num[N],pos[N],g[N],h[N],inv[N],mp[N][N],vis[M],lg[M];
ll n,c,len,a[N];int k,m,iv,lim,res;
inline bool cmp(const int &x,const int &y){return a[x]<a[y];}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%lld%d%d%lld",&n,&k,&m,&c),c%=P,iv=ksm(c,P-2),lim=(1<<k);
fp(i,0,k-1)scanf("%lld",&a[i]),num[i]=i;
sort(num,num+k,cmp);
fp(i,0,k-1){
pos[num[i]+1]=i,len=a[num[(i+1)%k]]-a[num[i]];
if(i==k-1)len+=n;
if(len&1){
same[i]=mul(iv,dec(ksm(c-1,len),c-1)),
diff[i]=mul(iv,add(ksm(c-1,len),1));
}else{
same[i]=mul(iv,add(ksm(c-1,len),c-1)),
diff[i]=mul(iv,dec(ksm(c-1,len),1));
}
}
for(R int i=1,u,v;i<=m;++i)scanf("%d%d",&u,&v),mp[pos[u]][pos[v]]=mp[pos[v]][pos[u]]=1;
vis[0]=1,f[0][0]=1;
for(R int i=2;i<lim;i<<=1)lg[i]=lg[i>>1]+1;
fp(s,1,lim-1){
vis[s]=1,sz[s]=sz[s>>1]+(s&1);
int u=lg[s&-s];
if(!vis[s^(s&-s)]){vis[s]=0;continue;}
fp(v,u+1,k-1)if(s>>v&1)vis[s]&=!mp[u][v];
if(!vis[s])continue;
f[s][sz[s]]=1;
fp(i,0,k-1)if(s>>i&1){
int v=(i+1)%k;
f[s][sz[s]]=mul(f[s][sz[s]],(s>>v&1)?same[i]:diff[i]);
}
}
for(R int i=1;i<lim;i<<=1)
for(R int j=0;j<lim;j+=(i<<1))
fp(l,0,i-1)
fp(s,0,k)f[i+j+l][s]=add(f[i+j+l][s],f[j+l][s]);
inv[0]=inv[1]=1;
fp(i,2,k)inv[i]=mul(P-P/i,inv[P%i]);
fp(s,0,lim-1){
fp(i,0,k)h[i]=f[s][i];
--h[0];
fp(i,0,k){
g[i]=0;
fp(j,0,i)g[i]=add(g[i],mul(h[i-j],g[j]));
g[i]=dec(mul(h[i+1],i+1),g[i]);
}
fd(i,k,1)g[i]=mul(g[i-1],inv[i]);g[0]=0;
fp(i,1,k)g[i]=mul(g[i],c);
fp(i,1,k)g[i-1]=mul(g[i],i);g[k]=0;
h[0]=1;
fp(i,0,k-1){
int res=0;
fp(j,0,i)res=add(res,mul(g[i-j],h[j]));
h[i+1]=mul(res,inv[i+1]);
}
((k-sz[s])&1)?res=dec(res,h[k]):res=add(res,h[k]);
}
printf("%d\n",res);
return 0;
}

NOI2019省选模拟赛 第五场的更多相关文章

  1. NOI2019省选模拟赛 第六场

    传送门 又炸了-- \(A\) 唐时月夜 不知道改了什么东西之后就\(A\)掉了\(.jpg\) 首先,题目保证"如果一片子水域曾经被操作过,那么在之后的施法中,这片子水域也一定会被操作&q ...

  2. NOI2019省选模拟赛 第三场

    传送门 明明没参加过却因为点进去结果狂掉\(rating\)-- \(A\) 集合 如果我们记 \[f_k=\sum_{i=1}^nT^i{n-i\choose k}\] 那么答案显然就是\(f_{k ...

  3. NOI.AC NOIP模拟赛 第五场 游记

    NOI.AC NOIP模拟赛 第五场 游记 count 题目大意: 长度为\(n+1(n\le10^5)\)的序列\(A\),其中的每个数都是不大于\(n\)的正整数,且\(n\)以内每个正整数至少出 ...

  4. [NOI.AC]NOI2019省选模拟赛 第二场

    传送门 Solution A. 一共有\(T\)组数据 每次询问你\([l,r]\)中有多少个数能被他的所有数位整除(如果数位中含有\(0\)忽略掉) 数位dp,咕咕咕 B. 题面略 考虑一个个只有两 ...

  5. 牛客网提高组模拟赛第五场 T1同余方程(异或)(位运算)

    区间不好做,但是我们可以转化成前缀来做.转化为前缀之后之后就是二维前缀和. 但是我还是不怎么会做.所以只能去看吉老师的题解 (确定写的那么简单真的是题解???). 我们要求模一个数余0,就等于找它的倍 ...

  6. [noi.ac省选模拟赛]第12场题解集合

    题目 比赛界面. T1 数据范围明示直接\(O(n^2)\)计算,问题就在如何快速计算. 树上路径统计通常会用到差分方法.这里有两棵树,因此我们可以做"差分套差分",在 A 树上对 ...

  7. [noi.ac省选模拟赛]第10场题解集合

    题目 比赛界面. T1 不难想到,对于一个与\(k\)根棍子连接的轨道,我们可以将它拆分成\(k+1\)个点,表示这条轨道不同的\(k+1\)段. 那么,棍子就成为了点与点之间的边.可以发现,按照棍子 ...

  8. [noi.ac省选模拟赛]第11场题解集合

    题目   比赛界面. T1   比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配.   尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...

  9. NOI.AC NOIP模拟赛 第六场 游记

    NOI.AC NOIP模拟赛 第六场 游记 queen 题目大意: 在一个\(n\times n(n\le10^5)\)的棋盘上,放有\(m(m\le10^5)\)个皇后,其中每一个皇后都可以向上.下 ...

随机推荐

  1. idea提示,格式化代码,清除不使用的包快捷键,maven自动导jar包

    一.提示快捷键 idea默认快捷键是ctrl+space,通常和别的软件快捷键冲突,所以将快捷键修改为alt+/ 二.格式化快捷键ctrl+alt+l,通常和qq.tim快捷键冲突,请修改qq或者ti ...

  2. 10个实用的UX设计作品推销小窍门

    以下内容由Mockplus(摹客)团队翻译整理,仅供学习交流,Mockplus是更快更简单的原型设计工具. 众所周知,产品用户体验很重要,即使是Google也知道这一点.但是,当真正涉及到UX 设计销 ...

  3. 玩转Sketch,不容错过的5大实用插件推荐

    在之前的文章中,笔者为大家介绍了Sketch 的入门教程.实用技巧和资源集锦,相信大家对Sketch已经有了初步的了解和认识.除了基础的矢量设计功能以外,插件更是让Sketch保持强大的独门秘籍.Sk ...

  4. linux git server 简易搭建 (ssh访问)

    git的服务器搭建,如果无需权限控制,仅团队内部使用,初始化一个服务器仓库,其他人通过ssh访问这个文件夹即可.如需复杂的管理,建议使用gitlab. yum install git -y id gi ...

  5. DB2日期转格式化字符串

    DB2  应该有个  TO_CHAR  的函数. 用来把 日期 转换为 字符串 1 2 3 4 5 6 7 8 9 10 db2 => SELECT db2 (cont.) =>   TO ...

  6. http头部信息

    1.常见的返回码 100: 请服务器端继续返回 200:成功 301:永久重定向 存的地址永久的改变了  301 302 : 暂时重定向 302仍然使用老得url 401 : 无法找到资源file n ...

  7. metasploit-数据库支持

    db_status db_disconnect db_connect 用户名:口令@服务器地址:端口/数据库名称 createdb msf4 -E UTF8 -T template0 -o msf3 ...

  8. console.dir(someObject);

    <script type="text/javascript"> function test(){ var array = [{"id":1},{&q ...

  9. (转)【经验之谈】Git使用之TortoiseGit配置VS详解

    原文地址:http://www.cnblogs.com/xishuai/p/3590705.html 前言 上一篇<[经验之谈]Git使用之Windows环境下配置>: 安装 配置和使用 ...

  10. Linux 基础教程 32-解压缩命令

        将文件压缩后对提升数据传输效率,降低传输带宽,管理备份数据都有非常重要的功能,因此文件压缩解压技能就成为必备技能.相对于Windows中的文件解压缩工具百花争艳,在Linux中的解压缩工具则要 ...