未分类 - ShinriiTin's Blog - 博主是sb

codeforces 442D Adam and Tree

题意:

给出一棵树,最开始只有1个节点。

每个时刻,这棵树会长出一个叶子。

树上每条边都有且只有1种颜色,并且同一种颜色的边都连通。

定义一个点到根的距离为该点到根的路径上的颜色种数。

求每个时刻树上最大距离的最小值。

 

分析:

考虑每次向上更新dp值,直到更新到根或者不能更新为止。

由树链剖分可知这样做的复杂度是O(nlogn)的。

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int MAXN=1e6+5;

int n;

int dp[MAXN],p[MAXN];

int mx1[MAXN],mx2[MAXN];

int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout); 
	scanf("%d",&n);
	puts("0");
	for(int i=2;i<=n;++i){
		scanf("%d",p+i);
		dp[i]=1;
		int cur=i;
		while(cur!=1){
			int par=p[cur];
			if(dp[cur]>mx1[par]){
				mx2[par]=mx1[par];
				mx1[par]=dp[cur];
			}
			else if(dp[cur]>mx2[par]){
				mx2[par]=dp[cur];
			}
			cur=par;
			int res=max(mx1[cur],mx2[cur]+1);
			if(res==dp[cur])break;
			dp[cur]=res;
		}
		printf("%d\n",mx1[1]);
	}
	return 0;
}

Link

题意:

有n(n<=20000)个小球,最开始都未被染色。

进行m(m<=20000)次操作,操作分为2种类型。

0.回到第x次操作的状态

1.将小球x和y所在的集合合并

然后进行k(k<=20000)次染色操作。

第i次染色操作将时间ti时xi所在连通块中最多zi个小球染色。

如果一个小球被染色了,那么任意时刻它都被染色了。

求最多能将多少小球染色。

 

分析:

很容易想到网络流的做法,但是一般的建图方法的点数和边数都无法接受。

考虑用可持久化的思想优化网络流建图。

首先处理连通性时我们会用到用主席树实现的可持久化并查集。

注意,这时不能使用路径压缩,要按秩合并来优化。

然后可以发现可持久化并查集就可以来优化建图了。

我们只考虑叶子。

S向最初版本的每个叶子连容量1的边。

每次更新时将历史版本向当前版本连容量为+∞的边;

合并时,向集合代表元连容量为+∞的边。

每次染色时,找到ti版本xi所在集合的代表元,向T连容量为zi的边。

然后跑最大流就行了。

 

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define S 1
#define T 2
#define inf 0x7f7f7f7f
#define gap(i) e[i].c-e[i].f
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c; while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

#define rep(i,a,b) for(int i=a;i<b;++i)

const int MAXN=80005;

int Id=2;

typedef struct node*star;

struct node{
	int f,id,sz;
	star ch[2];
}pool[MAXN*20];
star tail=pool;

inline star query(star x,int l,int r,int pos){
	while(l<r){
		int mid=(l+r)>>1,d=pos>mid;
		if(d)l=mid+1; else r=mid;
		x=x->ch[d];
	}
	return x;
}

int n,m,k,Head[MAXN];

star rt[MAXN];

struct edge{
	int t,c,f,n;
	edge(int t=0,int c=0,int n=0):
		t(t),c(c),f(0),n(n){}
}e[MAXN<<2];
int head[MAXN],tot=1;
inline void AddEdge(int s,int t,int c=1){
	e[++tot]=edge(t,c,head[s]),head[s]=tot;
	e[++tot]=edge(s,0,head[t]),head[t]=tot;
}

void build(star&x,int l,int r){
	x=tail++;
	if(l==r){
		x->f=l,x->sz=1;
		AddEdge(S,x->id=++Id);
		return;
	}
	int mid=(l+r)>>1;
	build(x->ch[0],l,mid);
	build(x->ch[1],mid+1,r);
}

void update(star&y,star x,int l,int r,int t,int f,int v){
	y=++tail; *y=*x;
	if(l==r){
		y->f=f,y->sz+=v;		
		AddEdge(x->id,y->id=++Id,inf);		
		return;
	}
	int mid=(l+r)>>1,d=t>mid;
	if(d)l=mid+1; else r=mid;
	update(y->ch[d],x->ch[d],l,r,t,f,v);
}

star find(int idx,int x){
	star res=query(rt[idx],1,n,x);
	return res->f==x?res:find(idx,res->f);
}

inline void Init(){
	Scan(n),Scan(m),Scan(k);
	build(rt[0],1,n);
}

inline void Merge(int idx,int x,int y){
	star fx=find(idx,x);
	star fy=find(idx,y);
	if(fx->f==fy->f)return;
	if(fx->sz>fy->sz)swap(fx,fy);
	update(rt[idx],rt[idx],1,n,fx->f,fy->f,0);
	update(rt[idx],rt[idx],1,n,fy->f,fy->f,fx->sz);
	fx=query(rt[idx],1,n,fx->f);
	fy=query(rt[idx],1,n,fy->f);
	AddEdge(fx->id,fy->id,inf);
}

int d[MAXN],p[MAXN],q[MAXN];

int cur[MAXN],g[MAXN];

inline int isap(int s,int t,int n){
	rep(i,1,n+1)d[i]=n;
	int tail=1;
	q[1]=t; d[t]=0;
	rep(h,1,tail+1){
		int x=q[h];
		++g[d[x]],cur[x]=head[x];
		for(int i=head[x],y;i;i=e[i].n)	
			if(!e[i].c&&d[y=e[i].t]==n){
				d[y]=d[x]+1;
				q[++tail]=y;
			}
	}
	int flow=0,x=s,a,f;
	while(d[s]<n){
		if(x==t){
			a=inf;
			for(int i=t;i!=s;i=e[p[i]^1].t)
				a=min(a,gap(p[i]));
			for(int i=t;i!=s;i=e[p[i]^1].t)
				e[p[i]].f+=a,e[p[i]^1].f-=a;
			flow+=a;
			x=s;
		}
		f=1;
		for(int&i=cur[x];i;i=e[i].n)
			if(gap(i)&&d[x]==d[e[i].t]+1){
				f=0;
				p[x=e[i].t]=i;
				break;
			}
		if(f){
			if(!(--g[d[x]]))break;
			f=n-1;
			for(int i=head[x];i;i=e[i].n)
				if(gap(i))f=min(f,d[e[i].t]);
			++g[d[x]=f+1];
			cur[x]=head[x];
			if(x!=s)x=e[p[x]^1].t;
		}
	}
	return flow;
}

inline void Solve(){
	rep(i,1,m+1){
		rt[i]=rt[i-1];
		int t,x,y; 
		Scan(t),Scan(x);
		if(t)Scan(y),Merge(i,x,y);
		else rt[i]=rt[x];	
	}
	rep(i,0,k){
		int x,y,w;
		Scan(x),Scan(y),Scan(w);
		star f=find(x,y);
		AddEdge(f->id,T,w);
	}
	printf("%d\n",isap(S,T,Id));
}

int main(){
	freopen("link.in","r",stdin);
	freopen("link.out","w",stdout);
	Init(); Solve(); return 0;
} 

Run

题意:

给出一张图(点数为n,边数为m)的一个生成树和一些非树边。

每条非树边有一个代价w,表示炸毁这条边需要付出的代价。

求炸毁一些非树边使得图中不存在偶环所付出的最小代价。

特别地,生成树上点的度数不超过10.

数据范围:n<=1000,m<=4000

 

分析:

首先如果一条非树边跨越了树上奇数条边,则这条边必须炸毁。

剩下的边,如果任意两条边所跨越的树上路径有公共边,则会存在偶环。

 

考虑到每个节点的儿子最多只有10个,我们可以考虑状压dp.

令f[x][s]表示以x为根的子树,只考虑集合s中儿子时能保留的边的最大权值。

令g[x][i]表示以x为根的子树,不考虑x的第i个儿子时能保留的边的最大权值。

每条非树边,只在它的端点的lca处考虑影响。

为了让路径不重复,则该非树边所覆盖的路径都不能被选。

暴力从一个端点到lca统计不考虑路径上的边时的最大权值。

再与该非树边没有覆盖的部分一起更新答案。

复杂度O(n*210+n*m)

 

#include <vector>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
}

#define Max(x,y) if(x<y)x=y
#define Min(x,y) if(x>y)x=y 
#define pb push_back
#define rep(i,a,b) for(int i=a;i<b;++i)

const int MAXN=1005;
const int MAXS=1<<10;

int n,m;

struct edge{
	int t,n;
	edge(int t=0,int n=0):t(t),n(n){}
}e[MAXN<<1];
int head[MAXN],tot;
inline void AddEdge(int s,int t){
	e[++tot]=edge(t,head[s]),head[s]=tot;
	e[++tot]=edge(s,head[t]),head[t]=tot;
}

int p[MAXN],dep[MAXN];

vector<int>ch[MAXN],qy[MAXN];

void dfs(int x){
	for(int i=head[x],y;i;i=e[i].n)
		if((y=e[i].t)!=p[x]){
			p[y]=x;
			dep[y]=dep[x]+1;
			ch[x].pb(y);
			dfs(y);
		}
}

inline int lca(int x,int y){
	if(dep[x]>dep[y])swap(x,y);
	while(dep[y]>dep[x])y=p[y];
	while(p[x]!=p[y])x=p[x],y=p[y];
	return x==y?x:p[x];
}

struct edge1{
	int u,v,w;
	inline void scan(){
		Scan(u),Scan(v),Scan(w);
	}
}tmp[MAXN*5];

int ans;

inline void Init(){
	Scan(n),Scan(m);
	rep(i,1,m+1){
		tmp[i].scan();
		ans+=tmp[i].w;
		if(!tmp[i].w){
			AddEdge(tmp[i].u,tmp[i].v);
		}
	}
	dfs(1);
	rep(i,1,m+1){
		if(!tmp[i].w)continue;
		int u=tmp[i].u,v=tmp[i].v;
		int Lca=lca(u,v);
		if((dep[u]+dep[v]-dep[Lca]*2)&1)continue;
		qy[Lca].pb(i);
	}
}

int dp[MAXN];

int f[MAXN][MAXS],g[MAXN][10];

inline int swim(int x,int par,int&res){
	int ban=-1;
	while(x!=par){
		if(~ban)res+=g[x][ban];
		else res+=dp[x];
		int s=ch[p[x]].size();
		rep(i,0,s)
			if(x==ch[p[x]][i]){
				ban=i; break;
			} 
		x=p[x];
	}
	return ban;
}

void tree_dp(int x){
	for(int i=head[x],y;i;i=e[i].n)
		if((y=e[i].t)!=p[x])tree_dp(y);
	int s=ch[x].size();
	int maxs=1<<s;
	rep(set,0,maxs){
		int res=0;
		rep(i,0,s)
			if(set>>i&1){
				res+=dp[ch[x][i]];
			}
		Max(f[x][set],res);
	}
	int c=qy[x].size();
	rep(i,0,c){
		int u=tmp[qy[x][i]].u;
		int v=tmp[qy[x][i]].v;
		int res=tmp[qy[x][i]].w;
		int bu=max(0,1<<swim(u,x,res));
		int bv=max(0,1<<swim(v,x,res));
		rep(set,0,maxs){
			if(bu&&(set&bu)==bu||bv&&(set&bv)==bv)
				continue;
			int ns=set^bu^bv;
			Max(f[x][ns],res+f[x][set]);
		}
	}
	rep(set,0,maxs){
		rep(i,0,s)
			if(!(set>>i&1)){
				Max(g[x][i],f[x][set]);
			}
		Max(dp[x],f[x][set]);
	}
}

inline void Solve(){
	tree_dp(1);
	ans-=dp[1];
	printf("%d\n",ans);
}

int main(){
	freopen("run.in","r",stdin);
	freopen("run.out","w",stdout);
	Init(); Solve(); return 0;
} 

听说下雨天,分块和莫队更配哦~

恩。。。先跪PoPoQQQ

 

bzoj3585 mex

题目大意:  询问区间mex值

这题有用线段树的O(nlogn)做法,以前发过了,所以这里不做讨论

既然是区间询问且支持离线的数据结构题,我们很容易想到用莫队算法。

那么问题就在于区间之间如何转移。

想法1: 用平衡树维护插入和删除,询问时在平衡树上二分。

这样做每次插入、删除和询问都是O(logn)的

由于莫队算法需要进行O(q*sqrt(n))次插入或删除,则总的复杂度会达到O(q*sqrt(n)*logn).

这个做法的瓶颈在于插入和删除时的花费太大。

想法2: 将权值分块,维护每种权值出现的次数和每块有多少种权值出现。

这样可以做到每次O(1)的插入和删除,插入和删除的总

询问时先暴力找到第一个存在未存在的数的块,再在这个块内暴力,复杂度O(sqrt(n))。

虽然询问的复杂度高于上一种做法,但是实际上询问只会有q次,总的复杂度依然是O(n*sqrt(n)).

Portal

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
}

#define rep(i,a,b) for(int i=a;i<b;++i)

const int MAXN=2e5+5;

int n,m,B,tot;

int a[MAXN],pos[MAXN];

struct qy{
	int l,r,id;
}q[MAXN];
inline bool cmp(const qy&a,const qy&b){
	if(pos[a.l]!=pos[b.l])return a.l<b.l;
	return pos[a.l]&1?a.r<b.r:a.r>b.r;
}

inline void Init(){
	Scan(n),Scan(m);
	B=sqrt(n)+1;
	tot=n/B+1;
	rep(i,1,n+1){
		Scan(a[i]);
		if(a[i]>n)a[i]=n;
	}
	rep(i,0,n+1)pos[i]=i/B+1;
	rep(i,1,m+1){
		Scan(q[i].l),Scan(q[i].r);
		q[i].id=i;
	} 
}

int cnt[MAXN],cnt1[MAXN]; 

inline void Add(int x){
	if(++cnt[x]==1)++cnt1[pos[x]];
}
inline void Del(int x){
	if(!(--cnt[x]))--cnt1[pos[x]];
}
inline int query(){
	int i=1;
	for(;i<=tot&&cnt1[i]==B;++i); 
	for(i=(i-1)*B;cnt[i]&&i<n;++i);
	return i; 
}

int ans[MAXN];

inline void Solve(){
	sort(q+1,q+1+m,cmp);
	int l=q[1].l,r=q[1].r;
	rep(i,l,r+1)Add(a[i]);
	ans[q[1].id]=query();
	rep(i,2,m+1){
		int ll=q[i].l,rr=q[i].r;
		for(;r<rr;Add(a[++r]));
		for(;r>rr;Del(a[r--]));
		for(;l>ll;Add(a[--l]));
		for(;l<ll;Del(a[l++]));
		ans[q[i].id]=query();
	}
	rep(i,1,m+1)
		printf("%d\n",ans[i]);
}

int main(){
	Init(); Solve(); return 0;
}

 

bzoj4129 Haruna's Breakfast

题目大意: 询问树上两点间路径的mex值,支持单点修改

这题是上一题的加强版,从线形推广到树形。

这题如果从线段树入手会十分困难(其实是博主太弱了不会这样做,有会这种做法的请联系我)

考虑到莫队算法是可以推广到树上的,我们直接用上一题的思路就好了。

由于带修改,对树分块时块的大小最好设为n2/3,对权值分块还是sqrt(n)就好。

简单说下树上路径的转移方法,为了方便,以下所说的路径均不含lca。

假设现在的路径是(x1,y1),需要转移到路径(x2,y2).

我们将路径(x1,x2),(y1,y2)取反,就得到了(x2,y2).

Portal

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
    char c; while(c=g(),c<48||c>57);
    for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

#define rep(i,a,b) for(int i=a;i<b;++i)

const int MAXN=50005;

int B1,Bn,a[MAXN],pos[MAXN];

struct edge{
    int t,n;
    edge(int t=0,int n=0):t(t),n(n){}
}e[MAXN<<1];
int head[MAXN],tot;
inline void AddEdge(int s,int t){
    e[++tot]=edge(t,head[s]),head[s]=tot;
    e[++tot]=edge(s,head[t]),head[t]=tot;
}

int n,m,B2,bel[MAXN],siz[MAXN];

struct qy{
    int x,y,z,id;
    qy(int x=0,int y=0,int z=0,int id=0):
		x(x),y(y),z(z),id(id){} 
}q[MAXN];

inline bool cmp(const qy&a,const qy&b){
    if(bel[a.x]!=bel[b.x])return bel[a.x]<bel[b.x];
    if(bel[a.y]!=bel[b.y])
		return bel[a.x]&1?bel[a.y]<bel[b.y]:bel[a.y]>bel[b.y];
    return bel[a.y]&1?a.z<b.z:a.z>b.z;
}

struct tarjan{
    int x,id,n;
    tarjan(int x=0,int id=0,int n=0):x(x),id(id),n(n){}
}t[MAXN<<1];
int thd[MAXN],qtot;
inline void AddTarjan(int x,int y,int id){
    t[++qtot]=tarjan(y,id,thd[x]),thd[x]=qtot;
    t[++qtot]=tarjan(x,id,thd[y]),thd[y]=qtot;
}

bool col[MAXN];

int f[MAXN];
int find(int x){
    return x==f[x]?x:f[x]=find(f[x]);
}

int p[MAXN],dep[MAXN],lca[MAXN];

void dfs(int x){
    for(int i=head[x],y;i;i=e[i].n)
        if((y=e[i].t)!=p[x]){
            if(siz[bel[x]]<B2){
                ++siz[bel[y]=bel[x]];
            }
            p[y]=x;
            dep[y]=dep[x]+1;
            dfs(y);
        }
    col[x]=1;
    for(int i=thd[x],y;i;i=t[i].n)
        if(col[y=t[i].x])lca[t[i].id]=find(y);
    f[x]=p[x];
}

bool on[MAXN];

int cnt[MAXN],cnt1[MAXN];

inline void Add(int x){
    if(++cnt[x]==1)++cnt1[pos[x]];
}
inline void Del(int x){
    if(--cnt[x]==0)--cnt1[pos[x]];
}
inline int query(){
	int i=1;
	for(;i<Bn&&cnt1[i]==B1;++i);
	for(i=(i-1)*B1;i<n&&cnt[i];++i);
	return i;
}

inline void Xor(int x){
    on[x]^=1;
    if(on[x])Add(a[x]);
    else Del(a[x]);
}

struct modify{
    int x,f,t;
    modify(int x=0,int f=0,int t=0):
    	x(x),f(f),t(t){}
}mo[MAXN];

int mod_tot,qy_tot;

inline void change(int x,int y){
    if(on[x])Del(a[x]);
    a[x]=y;
    if(on[x])Add(a[x]);
}
inline void Modify(int cur,int to){
    for(;cur<to;++cur)change(mo[cur+1].x,mo[cur+1].t);
    for(;cur>to;--cur)change(mo[cur].x,mo[cur].f);
}

inline void Rev(int x,int y){
    if(dep[x]>dep[y])swap(x,y);
    while(dep[y]>dep[x])Xor(y),y=p[y];
    while(x!=y)Xor(x),Xor(y),x=p[x],y=p[y];
}

int ans[MAXN];

inline void Init(){
    Scan(n),Scan(m);
    B1=sqrt(n),Bn=n/B1+1;
    B2=pow(n,2./3);
    pos[0]=1;
    rep(i,1,n+1){
    	pos[i]=i/B1+1;
        Scan(a[i]);
        if(a[i]>n)a[i]=n;
    	f[i]=bel[i]=i;   
    }
    rep(i,1,n){
        int x,y;
        Scan(x),Scan(y);
        AddEdge(x,y);
    }
    rep(i,1,m+1){
        int t,x,y;
        Scan(t),Scan(x),Scan(y);
        if(t){
			++qy_tot;
			q[qy_tot]=qy(x,y,mod_tot,qy_tot);
			AddTarjan(x,y,qy_tot);
        }
		else{
			if(y>n)y=n;
			mo[++mod_tot]=modify(x,a[x],y);
			a[x]=y;
		}
    }
    dfs(1);
    rep(i,1,qy_tot+1){
		if(bel[q[i].x]>bel[q[i].y])
			swap(q[i].x,q[i].y); 
	} 
}

inline void Solve(){
	sort(q+1,q+1+qy_tot,cmp);
	int x=q[1].x,y=q[1].y,z=q[1].z;
	int Lca=lca[q[1].id];
	Modify(mod_tot,z);
	Rev(x,y);
	Xor(Lca);
	ans[q[1].id]=query();
	Xor(Lca);
	rep(i,2,qy_tot+1){
		Modify(z,q[i].z),z=q[i].z;
		Rev(x,q[i].x),x=q[i].x;
		Rev(y,q[i].y),y=q[i].y;
		Lca=lca[q[i].id];
		Xor(Lca);
		ans[q[i].id]=query();
		Xor(Lca);
	}
	rep(i,1,qy_tot+1){
		printf("%d\n",ans[i]);
	} 
}

int main(){
	Init(); Solve(); return 0;
}

存一下最近几场比赛的代码

太弱没脸发题解,反正有官方题解对吧

 

CH弱省胡策

r3:

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define eps 1e-8
using namespace std;

#define rep(i,a,b) for(int i=a;i<=b;++i)

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
} 

const int MAXN=5e5+5;
const int MAXM=3005;

struct edge{
	int t,n;
	edge(int t=0,int n=0):t(t),n(n){}
}e[MAXN];
int head[MAXN];
inline void AddEdge(int s,int t){
	static int o=1;
	e[o]=edge(t,head[s]),head[s]=o++;
}

int par[MAXN][20],dep[MAXN];

int rt;

void prev(int x){
	if(dep[x])return;
	if(~*par[x]){
		prev(*par[x]);
		AddEdge(*par[x],x);
		dep[x]=dep[*par[x]]+1;
		for(int i=0;par[x][i];++i)
			par[x][i+1]=par[par[x][i]][i]; 
	}
	else rt=x,dep[x]=1;
}

int B[MAXN],R[MAXN];

int b[MAXN],r[MAXN],w[MAXN];

bool u[MAXN];

int n,m,k,l;

inline int swim(int x,int h){
	for(int i=0;h;++i,h>>=1)
		if(h&1)x=par[x][i];
	return x;
}

void dp(int x){
	for(int i=head[x],y;i;i=e[i].n){
		dp(y=e[i].t);
		B[x]+=B[y],R[x]+=R[y];
	}
}

typedef double db;
const db pi=acos(-1.);
#define sqr(x) (db(x)*(x))

struct poi{
	int x,y,w;
	poi(int x=0,int y=0,int w=0):
		x(x),y(y),w(w){}
	inline db alpha(){return atan2(y,x);}
}p[MAXM];

inline poi operator-(const poi&a,const poi&b){
	return poi(a.x-b.x,a.y-b.y);
}

inline void Init(){
	Scan(n),Scan(k),Scan(l);
	rep(i,1,n){
		Scan(b[i]),Scan(r[i]);
		Scan(w[i]),Scan(*par[i]),Scan(u[i]);
	}
	rep(i,1,n)prev(i);
	rep(i,1,n){
		B[i]+=b[i],R[i]+=r[i];
		if(dep[i]<=k)continue;
		int y=swim(i,k);
		B[y]-=b[i],R[y]-=r[i];
	}
	dp(rt);
	rep(i,1,n)
		if(u[i])p[++m]=poi(B[i],R[i],w[i]);
}

inline db normalize(db x){
	while(x<-pi)x+=pi*2.;
	while(x>=pi)x-=pi*2.;
	return x;
}

struct event{
	db alpha;
	int w;
	event(db alpha=0,int w=0):alpha(alpha),w(w){}
}eve[MAXM<<2];
int tot;

inline bool cmp(const event&a,const event&b){
	return a.alpha!=b.alpha?a.alpha<b.alpha:a.w>b.w; 
}

inline db dis(const poi&a,const poi&b){
	return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}

inline int calc(int x){
	tot=0;
	rep(i,1,m){
		if(i==x)continue;
		db L=dis(p[x],p[i]);
		if(L-l*2>eps)continue;
		db alpha=(p[i]-p[x]).alpha();
		db delta=acos(L/(l*2));
		db s=normalize(alpha-delta);
		db t=normalize(alpha+delta);
		eve[++tot]=event(s,p[i].w);
		eve[++tot]=event(t,-p[i].w);
		if(s>t){
			eve[++tot]=event(-pi,p[i].w);
			eve[++tot]=event(pi,-p[i].w);
		}
	}
	sort(eve+1,eve+1+tot,cmp);
	int res=0,sum=0;
	rep(i,1,tot){
		sum+=eve[i].w;
		res=max(res,sum);
	}
	return res+p[x].w;
}

inline void Solve(){
	int ans=0;
	rep(i,1,m)ans=max(ans,calc(i));
	printf("%d\n",ans);
}

int main(){
	Init(); Solve(); return 0;
}
#include <map>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define inv(x,P) qpow(x,P-2,P)
#define DFT(a,n,P) fft(a,n,0,P)
#define IDFT(a,n,P) fft(a,n,1,P)
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c; while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

const int MAXN=(1<<18)+5;
typedef unsigned long long ll;
const int P1=1004535809;
const int P2=998244353;
const int G=3;
const ll P=(ll)P1*P2;

inline ll qpow(ll x,ll k,ll M){
	ll ans=1;
	for(;k;x=x*x%M,k>>=1)
		if(k&1)ans=ans*x%M;
	return ans;
}

int w[2][MAXN],r[MAXN],rn;

inline void init_fft(int n,int bit,int P){
	rn=inv(n,P);
	int g=qpow(G,(P-1)/n,P);
	w[0][0]=w[0][n]=1;
	rep(i,1,n-1)w[0][i]=(ll)w[0][i-1]*g%P;
	rep(i,0,n)w[1][i]=w[0][n-i];
	rep(i,1,n)r[i]=(r[i>>1]>>1)|((i&1)<<(bit-1));
}

inline void fft(int*a,int n,int t,int P){
	rep(i,1,n)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=2;i<=n;i<<=1)
		for(int j=0;j<n;j+=i)
			for(int k=0;k<i>>1;++k){
				int re=(ll)a[(i>>1)+j+k]*w[t][n/i*k]%P;
				a[(i>>1)+j+k]=(a[j+k]+P-re)%P;
				a[j+k]=(a[j+k]+re)%P;
			}
	if(t)rep(i,0,n-1)a[i]=(ll)a[i]*rn%P;
}

bool ban[MAXN];

int p[MAXN],phi[MAXN],tot;

inline void get_phi(int n){
	phi[1]=1;
	rep(i,2,n){
		if(!ban[i]){
			p[++tot]=i;
			phi[i]=i-1;	
		}
		rep(j,1,tot){
			if((ll)i*p[j]>n)break;
			int x=i*p[j];
			ban[x]=1;
			if(i%p[j]){
				phi[x]=phi[i]*(p[j]-1);
			}
			else{
				phi[x]=phi[i]*p[j];
				break;
			}
		}
	}
	rep(i,1,n)phi[i]%=23;
}

inline ll qmul(ll a,ll b,ll M){
	ll ans=0;
	for(;b;b>>=1,a=(a<<1)%M)
		if(b&1)ans=(ans+a)%M;
	return ans;
}

const int r_P2=inv(P2,P1);
const int r_P1=inv(P1,P2);

inline ll crt(ll x1,ll x2){
	ll ans=0;
	ans+=qmul(qmul(x1,P2,P),r_P2,P);
	ans+=qmul(qmul(x2,P1,P),r_P1,P);
	return ans%P;
}

int n,len,bit;

int a[MAXN],c[MAXN];

map<int,int>g;

inline void Init(){
	Scan(n);
	get_phi(n);
	len=n<<1,bit=1;
	while(1<<bit<len)++bit;
	len=1<<bit;
	g[1]=0;
	int tmp=1;
	rep(i,1,100000){
		tmp=(ll)tmp*G%P1;
		g[tmp]=i;
	}
	rep(i,0,n-1){
		Scan(a[i]);
		if(i)a[i]=(a[i]+a[i-1])%P1;
	}
	rep(i,0,n-1)a[i]=g[a[i]];
}

int a1[MAXN],a2[MAXN];

int c1[MAXN],c2[MAXN];

inline void calc_C(){
	rep(i,0,n-1){
		a1[i]=a2[i]=a[i];
		c1[i]=c2[i]=phi[i];
	}
	
	init_fft(len,bit,P2);
	DFT(a2,len,P2),DFT(c2,len,P2);
	rep(i,0,len-1)c2[i]=(ll)a2[i]*c2[i]%P2;
	IDFT(c2,len,P2);
	
	init_fft(len,bit,P1);
	DFT(a1,len,P1),DFT(c1,len,P1);
	rep(i,0,len-1)c1[i]=(ll)a1[i]*c1[i]%P1;
	IDFT(c1,len,P1);
	rep(i,0,n-1)c[i]=qpow(G,crt(c1[i],c2[i])%(P1-1),P1);
	for(int i=n;i;--i)c[i]=c[i-1];
	c[0]=0;
}

inline void Solve(){
	calc_C();
	DFT(c,len,P1);
	rep(i,0,len-1)c[i]=(ll)c[i]*c[i]%P1;
	IDFT(c,len,P1);
	int ans=0;
	rep(i,0,n)ans=(ans+c[i])%P1;
	printf("%d\n",ans);
}

int main(){
	Init(); Solve(); return 0;
}
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,a,b) for(int i=a;i<=b;++i) 
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

const int MAXN=5e6+5;
const int Mod=1e9+7;
typedef long long ll;

bool ban[MAXN];

int p[MAXN],tot;

int fac[MAXN],fib[MAXN];

inline void get_prime(int n){
	fib[1]=fac[1]=1;
	rep(i,2,n){
		fib[i]=(fib[i-1]+fib[i-2])%Mod;
		if(!ban[i])p[++tot]=i,fac[i]=i;
		rep(j,1,tot){
			if(1ll*i*p[j]>n)break;
			ban[i*p[j]]=1;
			fac[i*p[j]]=p[j];
			if(!(i%p[j]))break;
		}
	}
}

int n,f[MAXN];

inline int gcd(int a,int b){
	for(;b;swap(a,b),b%=a);
	return a;
}

int ans,mx;

inline void Init(){
	get_prime(5e6);
	Scan(n);
	rep(i,1,n){
		int tp,x;Scan(tp);
		if(tp){
			int a,b;
			Scan(a),Scan(b);
			x=a+b-gcd(a,b);
		}
		else Scan(x);
		++f[x];
		ans=(ans+fib[x])%Mod;
		mx=max(x,mx);
	}
}

ll d[MAXN];

void div(int x,int cur,int v){
	if(x==1){
		d[cur]+=v;
		return;
	}
	else{
		int res=fac[x],cnt=0,tmp=1;
		for(;!(x%res);++cnt,x/=res);
		rep(i,0,cnt){
			div(x,cur*tmp,v);
			tmp*=res;
		}
	}
}

inline void Solve(){
	rep(i,1,mx)if(f[i])div(i,1,f[i]);
	for(int i=mx;i;--i){
		if(!d[i])continue;
		d[i]=d[i]*(d[i]-1)>>1;
		for(int j=i<<1;j<=mx;j+=i)d[i]-=d[j];
		ans=(ans+d[i]*fib[i]%Mod)%Mod;
	}
	printf("%d\n",ans);
}

int main(){
	Init(); Solve(); return 0;
}

r4

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define eps 1e-6
#define inf 1e20
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define fore(i,x) for(int i=head[x];i;i=e[i].n)if(e[i].c>e[i].f)
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
}

const int MAXN=2000;
typedef double db;

struct edge{
	int t;db c,f;int n;
	edge(int t=0,db c=0,db n=0):
		t(t),c(c),f(0),n(n){}
}e[MAXN<<2];
int head[MAXN],tot;
inline void AddEdge(int s,int t,db c){
	e[++tot]=edge(t,c,head[s]),head[s]=tot;
	e[++tot]=edge(s,0,head[t]),head[t]=tot;
}

int d[MAXN],p[MAXN],g[MAXN],cur[MAXN];

int q[MAXN];

inline db isap(int s,int t,int n){
	rep(i,1,n)d[i]=n;
	rep(i,0,n)g[i]=0;
	int tail=1;
	q[tail]=t,d[t]=0;
	for(int j=1;j<=tail;++j){
		int x=q[j];
		for(int i=head[x],y;i;i=e[i].n)
			if(!e[i].c&&d[y=e[i].t]==n){
				d[y]=d[x]+1;
				q[++tail]=y;
			}
	}
	rep(i,1,n){
		cur[i]=head[i],++g[d[i]];
	}
	db flow=0,a;int x=s,f;
	while(d[s]<n){
		if(x==t){
			a=inf;
			for(int i=t;i!=s;i=e[p[i]^1].t){
				a=min(a,e[p[i]].c-e[p[i]].f);
			}
			for(int i=t;i!=s;i=e[p[i]^1].t){
				e[p[i]].f+=a,e[p[i]^1].f-=a;
			}
			flow+=a;
			x=s;
		}
		f=1;
		for(int&i=cur[x];i;i=e[i].n)
			if(e[i].c>e[i].f&&d[x]==d[e[i].t]+1){
				f=0,p[x=e[i].t]=i; break;
			}
		if(f){
			if(!(--g[d[x]]))break;
			f=n-1;
			fore(i,x)f=min(f,d[e[i].t]);
			++g[d[x]=f+1];
			cur[x]=head[x];
			if(x!=s)x=e[p[x]^1].t;
		}
	}
	return flow; 
}

inline void clear(){
	memset(head,0,sizeof head);
	tot=1;
}

int n,m;
#define S n+m+1
#define T n+m+2

int c[MAXN];

int u[MAXN],v[MAXN],w[MAXN];

db sum;

inline void Init(){
	Scan(n),Scan(m);
	rep(i,1,n)Scan(c[i]);
	rep(i,1,m){
		Scan(u[i]),Scan(v[i]);
		Scan(w[i]);
	}
}

inline bool check(db x){
	clear();
	sum=0;
	rep(i,1,m){
		AddEdge(S,i+n,w[i]),sum+=w[i];
	}
	rep(i,1,n)AddEdge(i,T,x*c[i]);
	rep(i,1,m){
		AddEdge(i+n,u[i],inf);
		AddEdge(i+n,v[i],inf);
	}
	sum-=isap(S,T,T);
	return sum<eps;
}

inline void Solve(){
	db l=0,r=1e9;
	while(r-l>eps){
		db mid=(l+r)/2.;
		if(check(mid))r=mid;
		else l=mid;
	}
	printf("%.2f\n",l);
}

int main(){
	Init(); Solve(); return 0;
}
留坑QAQ
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define inf 0x7f7f7f7f
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
}

const int MAXN=50005;

struct edge{
	int t,n;
	edge(int t=0,int n=0):t(t),n(n){}
}e[MAXN<<1];
int head[MAXN],tot;
inline void AddEdge(int s,int t){
	e[++tot]=edge(t,head[s]),head[s]=tot;
	e[++tot]=edge(s,head[t]),head[t]=tot;
}

int sum[MAXN]={-1},dis[MAXN];

int n,p[MAXN],w[MAXN],mx[MAXN][2];

void dfs(int x){
	sum[x]=w[x];
	for(int i=head[x],y;i;i=e[i].n)
		if((y=e[i].t)!=p[x]){
			p[y]=x,dfs(y);
			sum[x]+=sum[y];
			dis[x]+=sum[y]+dis[y];
			if(sum[y]>sum[mx[x][0]]){
				mx[x][1]=mx[x][0];
				mx[x][0]=y;
			}
			else if(sum[y]>sum[mx[x][1]]){
				mx[x][1]=y;
			}
		}
}

int find(int x,int s=0,int c=0){
	int res=dis[x]+s+c;
	if(mx[x][0]){
		int y=mx[x][0];
		int ns=s+c+dis[x]-dis[y]-sum[y];
		int nc=c+sum[x]-sum[y];
		int tmp=dis[y]+ns+nc;
		if(tmp<res){
			return find(y,ns,nc);
		}
	}
	return res;
}

bool flag[MAXN];

void remove(int x){
	int y=p[x]; 
	flag[x]= x==mx[y][0];
	if(flag[x])mx[y][0]=mx[y][1];
	int t=dis[x];
	while(y){
		t+=sum[x];
		dis[y]-=t;
		sum[y]-=sum[x];
		flag[y]= y==mx[p[y]][0];
		if(flag[y]){
			if(sum[mx[p[y]][1]]>sum[y]){
				mx[p[y]][0]=mx[p[y]][1];
			}
		}
		y=p[y];
	}
}

void recover(int x){
	int y=p[x];
	if(flag[x])mx[y][0]=x;
	int t=dis[x];
	while(y){
		t+=sum[x];
		dis[y]+=t;
		sum[y]+=sum[x];
		if(flag[y])mx[p[y]][0]=y;
		y=p[y];
	}
}

int rt,ans=inf;

void dp(int x){
	for(int i=head[x],y;i;i=e[i].n)
		if((y=e[i].t)!=p[x]){
			remove(y);
			ans=min(ans,find(y)+find(rt));
			recover(y);
			dp(y);
		}
}

inline void Init(){
	Scan(n);
	for(int i=1,x,y;i<n;++i){
		Scan(x),Scan(y);
		AddEdge(x,y);
	}
	for(int i=1;i<=n;++i)Scan(w[i]);
	dfs(rt=1);
}

inline void Solve(){
	dp(rt);
	printf("%d\n",ans);
}

int main(){
	Init(); Solve(); return 0;
}

r5

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
}

#define DFT(a,n) fft(a,n,0)
#define IDFT(a,n) fft(a,n,1) 
#define rep(i,a,b) for(int i=a;i<b;++i)
typedef long long ll;
const int P=998244353;

inline ll qpow(ll x,int k){
	ll ans=1;
	for(;k;x=x*x%P,k>>=1)
		if(k&1)ans=ans*x%P;
	return ans; 
}

const int MAXN=(1<<18)+5;

int r[MAXN],w[2][MAXN],rn;

inline void init_fft(int n,int b){
	rn=qpow(n,P-2);
	int g=qpow(3,(P-1)/n);
	w[0][0]=w[0][n]=1;
	rep(i,1,n)w[0][i]=1ll*w[0][i-1]*g%P;
	rep(i,0,n+1)w[1][i]=w[0][n-i];
	rep(i,1,n){
		r[i]=(r[i>>1]>>1)|((i&1)<<(b-1));
	}
} 

inline void fft(int*a,int n,int t){
	rep(i,1,n)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=2;i<=n;i<<=1)
		for(int j=0;j<n;j+=i)
			for(int k=0;k<i>>1;++k){
				int v=1ll*a[(i>>1)+j+k]*w[t][n/i*k]%P;
				a[(i>>1)+j+k]=(a[j+k]+P-v)%P;
				a[j+k]=(a[j+k]+v)%P;
			}
	if(t)rep(i,0,n)a[i]=1ll*a[i]*rn%P;
}

int n,l,bit;

int a[MAXN],b[MAXN];

int fac[MAXN],inv[MAXN];

int x[MAXN],y[MAXN];

inline void Init(){
	Scan(n);
	rep(i,0,n+1)Scan(b[i]);
	l=n<<1|1,bit=1;
	while(1<<bit<l)++bit;
	l=1<<bit;
	init_fft(l,bit);
	fac[0]=1;
	rep(i,1,n+1)fac[i]=1ll*fac[i-1]*i%P;
	inv[0]=inv[1]=1;
	rep(i,2,n+1){
		int a=P/i,b=P%i;
		inv[i]=1ll*a*(P-inv[b])%P;
	}	
	rep(i,2,n+1)
		inv[i]=1ll*inv[i]*inv[i-1]%P;
}

inline void Solve(){
	rep(i,0,n+1){
		x[i]=1ll*fac[n-i]*b[n-i]%P;
		if((n-i)&1)if(x[i])x[i]=P-x[i];
	}
	rep(i,0,n+1)y[i]=inv[i];
	DFT(x,l),DFT(y,l);
	rep(i,0,l)x[i]=1ll*x[i]*y[i]%P;
	IDFT(x,l);
	rep(i,0,n+1){
		a[i]=1ll*inv[i]*x[n-i]%P;
		if(i&1)if(a[i])a[i]=P-a[i];
	}
	rep(i,0,n+1)printf("%d ",a[i]);
}

int main(){
	Init(); Solve(); return 0;
}
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
}

#define rep(i,a,b) for(int i=a;i<b;++i)

const int MAXN=305;

int n,k;

int e[MAXN][MAXN];

int main(){
	Scan(n),Scan(k);
	rep(i,1,n+1)e[i][i]=1; 
	int m=n-k+1;
	rep(i,1,m+1)rep(j,i+1,m+1)
		e[i][j]=e[j][i]=1;
	rep(i,m+1,n+1)e[i][i-1]=e[i-1][i]=1;
	rep(i,1,n+1){
		rep(j,1,n+1)putchar(e[i][j]+48);
		puts("");
	}
	return 0;
}
留坑QAQ

UOJ Round#8

#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lch x->l,l,mid
#define rch x->r,mid+1,r 
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c; while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

const int MAXN=2e5+5;

typedef struct node*star;

struct data{
	int l_iro,r_iro;
	int iro_cnt;
	data(int l_iro=0,int r_iro=0,int iro_cnt=0):
		l_iro(l_iro),r_iro(r_iro),iro_cnt(iro_cnt){}
};

inline data operator+(const data&a,const data&b){
	data c;
	c.l_iro=a.l_iro,c.r_iro=b.r_iro;
	c.iro_cnt=a.iro_cnt+b.iro_cnt;
	if(a.r_iro==b.l_iro)--c.iro_cnt;
	return c;
}

struct node{
	data d;
	star l,r;
}pool[MAXN<<4];

star tail=pool;

void build(int*a,star&x,int l,int r){
	x=tail++;
	if(l==r){
		x->d=data(a[l],a[l],1);
		return;
	}
	int mid=(l+r)>>1;
	build(a,lch),build(a,rch);
	x->d=x->l->d+x->r->d;
}

inline data query(star x,int l,int r,int ll,int rr){
	if(l==ll&&r==rr)return x->d;
	int mid=(l+r)>>1;
	if(rr<=mid)return query(lch,ll,rr);
	if(ll>mid) return query(rch,ll,rr);
	return query(lch,ll,mid)+query(rch,mid+1,rr); 
}

star rta,rtb;

int n,m,q,a[MAXN],b[MAXN];

int main(){
	Scan(n),Scan(m);
	for(int i=1;i<=n;++i)Scan(a[i]);
	for(int i=1;i<=n;++i)a[i+n]=a[i];
	build(a,rta,1,n<<1);
	for(int i=1;i<=m;++i)Scan(b[i]);
	for(int i=1;i<=m;++i)b[i+m]=b[i];
	build(b,rtb,1,m<<1);
	Scan(q);
	for(int i=1;i<=q;++i){
		int sx,sy,tx,ty;
		Scan(sx),Scan(sy),Scan(tx),Scan(ty);
		if(sx>tx)swap(sx,tx);
		if(sy>ty)swap(sy,ty);
		int t1=query(rta,1,n<<1,sx,tx).iro_cnt;
		t1=min(t1,query(rta,1,n<<1,tx,sx+n).iro_cnt);
		int t2=query(rtb,1,m<<1,sy,ty).iro_cnt;
		t2=min(t2,query(rtb,1,m<<1,ty,sy+m).iro_cnt);
		int ans=t1+t2-2;
		printf("%d\n",ans);
	}
	return 0;
}
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define lch x->l,l,mid
#define rch x->r,mid+1,r 
#define LL long long
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c; while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

const int MAXN=2e5+5;

typedef struct node*star;

struct data{
	int min,max;
	data(int min=0,int max=0):
		min(min),max(max){}
};

inline data operator+(const data&a,const data&b){
	return data(min(a.min,b.min),max(a.max,b.max)); 
}

struct node{
	data d;
	bool rev;
	inline void rev_it(){
		d.min=100000-d.min;
		d.max=100000-d.max;
		swap(d.min,d.max);
		rev^=1;
	}
	inline void down(){
		if(!rev)return;
		l->rev_it(),r->rev_it();
		rev=0;
	}
	inline void updt(){
		d=l->d+r->d;
	}
	star l,r;
}pool[MAXN<<4];

star tail=pool;

void build(int*a,star&x,int l,int r){
	x=tail++;
	if(l==r){
		x->d=data(a[l],a[l]);
		return;
	}
	int mid=(l+r)>>1;
	build(a,lch),build(a,rch);
	x->updt();
}

LL ans;

inline LL calc(int a,int b,int c,int x,int y){
	return 1ll*a*x+1ll*b*y+1ll*c*x*y;
}

inline void query(star x,int l,int r,int ll,int rr,int a,int b,int c){
	if(ll>r||rr<l)return;
	if(l==r){
		ans=max(ans,calc(a,b,c,l,x->d.max));
		return;	
	}
	LL g=calc(a,b,c,min(r,rr),x->d.max);
	if(g<=ans)return;
	int mid=(l+r)>>1;
	x->down();
	LL g1=calc(a,b,c,min(mid,rr),x->l->d.max);
	LL g2=calc(a,b,c,min(r,rr),x->r->d.max);
	if(g1>g2)query(lch,ll,rr,a,b,c),query(rch,ll,rr,a,b,c);
	else  query(rch,ll,rr,a,b,c),query(lch,ll,rr,a,b,c);
}

int y[MAXN];

inline void modify(star x,int l,int r,int pos,int y){
	if(l==r){
		x->d=data(y,y);
		return;
	}
	int mid=(l+r)>>1;
	x->down();
	if(pos>mid)modify(rch,pos,y);
	else modify(lch,pos,y);
	x->updt();
}

inline void modify1(star x,int l,int r,int ll,int rr){
	if(ll<=l&&r<=rr)return x->rev_it();
	x->down();
	int mid=(l+r)>>1;
	if(ll<=mid)modify1(lch,ll,rr);
	if(rr>mid) modify1(rch,ll,rr);
	x->updt();
}

int n,m,q,x0;

const int P=998244353;

inline int rand_x(){
	return (x0=((1ll*x0*100000005%P+20150609)%P))/100;
}

star rt;

inline void Solve(){
	build(y,rt,1,n);
	for(int i=1;i<=m;++i){
		char c;while(c=g(),c<'A'||c>'Z');
		if(c=='C'){
			int x=rand_x()%n+1;
			int y1=rand_x()%100001;
			modify(rt,1,n,x,y1);
		}
		else if(c=='R'){
			int l=rand_x()%n+1;
			int r=rand_x()%n+1;
			if(l>r)swap(l,r);
			modify1(rt,1,n,l,r);
		}
		else{
			int l=rand_x()%n+1;
			int r=rand_x()%n+1;
			if(l>r)swap(l,r);
			int a,b,c;
			Scan(a),Scan(b),Scan(c);
			ans=-1ll<<60;
			query(rt,1,n,l,r,a,b,c);
			printf("%lld\n",ans);
		}
	}
}

int main(){
	Scan(n),Scan(m),Scan(x0);
	for(int i=1;i<=n;++i)
		y[i]=rand_x()%100001;
	Solve();
	return 0;
}
留坑QAQ

TopCoder SRM518 Div1 1000 Nim

题意:

      有k(k<=109)堆石子,每堆石子的数量都是不大于L(L<=50000)的质数,

问有多少种初始状态是先手必败状态,mod 1000000007

 

定义卷积C=A*B,Cn=∑i,j [i^j=n]*Ai*Bj,则答案为[x0]Ak,其中Ai=[i为质数]

 

Fast Walsh Transform

 

考虑一种Transformation u(f),满足u(A)*u(B)=u(A*B),

并且存在u(f)的Inverse Transformation v(f),满足v(u(f))=f

 

假设向量x的长度为n

当n为1时,显然u(x)=x,因为0^0=0,满足u(A)*u(B)=u(A*B)

当n为2时,设A=(x1,y1),B=(x2,y2),则A*B=(x1*x2+y1*y2,x1*y2+x2*y1)

设x=(x1,x2),此时dwt(x)=(x1-x2,x1+x2)

dwt(A)*dwt(B)=((x1-y1)*(x2-y2),(x1+y1)*(x2+y2))=dwt(A*B)

对于n为大于等于2的2的整次幂,x=(x1,x2),x1和x2的长度为n/2

dwt(x)=(dwt(x1)-dwt(x2),dwt(x1)+dwt(x2))

 

令y=dwt(x),考虑其逆变换idwt(y)=x,当n=1时同理idwt(y)=y

当n为大于等于2的2的整次幂,y=(y1,y2),

解方程y1=dwt(x1)-dwt(x2),y2=dwt(x1)+dwt(x2)

解得:idwt(y)=(idwt((y1+y2)/2),idwt((y2-y1)/2))

 

虽然我并不清楚这是怎么想出来的,但是在知道有这个变换的情况下,

理解它的正确性还是比较容易的,而且它的形式也很优美呢。

 

class Nim{
	public:
		static const int MAXN=(1<<17)+5;
		static const int Mod=1e9+7;
		typedef long long ll;

		inline ll qpow(ll x,int k,int M){
			ll ans=1;
			for(;k;x=x*x%M,k>>=1)
				if(k&1)ans=ans*x%M;
			return ans;
		}

		int r2;

		int a[MAXN];

		void dwt(int l,int r){
			if(l==r)return;
			int mid=(l+r)>>1,len=r-mid;
			dwt(l,mid),dwt(mid+1,r);
			for(int i=l;i<=mid;++i){
				int x=a[i],y=a[i+len];
				a[i]=(x-y+Mod)%Mod;
				a[i+len]=(x+y)%Mod;
			}
		}

		void idwt(int l,int r){
			if(l==r)return;
			int mid=(l+r)>>1,len=r-mid;
			for(int i=l;i<=mid;++i){
				int x=1ll*a[i]*r2%Mod;
				int y=1ll*a[i+len]*r2%Mod;
				a[i]=(x+y)%Mod;
				a[i+len]=(y+Mod-x)%Mod;
			}
			idwt(l,mid),idwt(mid+1,r);
		}

		bool ban[MAXN];

		int p[MAXN],tot;

		inline void get_prime(int n){
			ban[1]=1;
			for(int i=2;i<=n;++i){
				if(!ban[i])p[++tot]=i;
				for(int j=1;j<=tot;++j){
					if(1ll*i*p[j]>n)break;
					ban[i*p[j]]=1;
				if(!(i%p[j]))break;
				}
			}
		}

		inline int count(int K,int L){
			r2=qpow(2,Mod-2,Mod);
			get_prime(L);
			for(int i=1;i<=L;++i)a[i]=!ban[i];
			int l=1<<16;
			dwt(0,l-1);
			for(int i=0;i<l;++i)
			a[i]=qpow(a[i],K,Mod);
			idwt(0,l-1);
			return a[0];
		}
};

codechef Milestones

题意:

平面上有n(n<=10000)个点,已知用7条直线就能完全覆盖它们.

求最多用1条直线可以覆盖多少个点

随机1000次就能过了。。。

Portal

#include <time.h>
#include <stdio.h>
#include <stdlib.h> 
#include <string.h>
#include <algorithm>
using namespace std;

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c;int f=1;
	while(c=g(),c<48||c>57)if(c=='-')f=-1;
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
	x*=f;
}

#define rep(i,a,b) for(int i=a;i<b;++i)
typedef int ll;

const int MAXN=10005;

struct poi{
	ll x,y;
	inline void scan(){
		Scan(x),Scan(y);
	}
	poi(ll x=0,ll y=0):x(x),y(y){}
}p[MAXN];

inline poi operator-(const poi&a,const poi&b){
	return poi(a.x-b.x,a.y-b.y);
}
inline ll cross(const poi&a,const poi&b){
	return a.x*b.y-a.y*b.x;
}

int T,n,ans;

inline int calc(int s,int t){
	if(s==t)(++t)%=n;
	int res=0;
	rep(i,0,n)
		if(!cross(p[i]-p[s],p[t]-p[s]))++res;
	return res;
} 

inline void Solve(){
	Scan(n);
	rep(i,0,n)p[i].scan();
	ans=0;
	rep(i,0,1000){
		ans=max(ans,calc(rand()%n,rand()%n));
	}
	printf("%d\n",ans);
}

int main(){
	srand(time(0));
	for(Scan(T);T--;Solve()); 
	return 0;
}

codeforces round290 Div1 E Fox And Polygon

题意:

给出一个正n边形和它的一个三角剖分.

要求通过每次选择两个相邻的三角形,将它们构成的四边形的对角线翻转

使得最后变为该正n边形的另一个三角剖分。

 

先找出将任意三角剖分化为同一个三角剖分的方法。

然后,就可以一个正着做,一个反着做来达到目的了。

将任意三角剖分化为以1号点为剖分点的扇形剖分,顺时针考虑每一个应该出现的剖分边,如果它不存在,

就找到一条阻碍它存在的剖分边,将它取反。

Portal

#include <vector>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int MAXN=1005; 

bool e[MAXN][MAXN];

int n;

inline void clear(){
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			e[i][j]=0;
}

typedef pair<int,int>op;
#define fi first
#define se second
#define mp make_pair
#define pb push_back

vector<op>s;

int type;

inline void Xor(int x,int y){
	for(int i=2;i<=n;++i)
		if(e[i][x]&&e[i][y]){
			e[x][y]=e[y][x]=0;
			e[1][i]=e[i][1]=1;
			if(!type)s.pb(mp(x,y));
			else s.pb(mp(1,i));
			break;
		}
}

inline void Solve(){
	clear();
	for(int i=3,x,y;i<n;++i){
		scanf("%d%d",&x,&y);
		e[x][y]=e[y][x]=1;
	}
	for(int i=1;i<=n;++i){
		int j=i+1;
		if(i==n)j=1;
		e[i][j]=e[j][i]=1;
	}
	s.clear();
	for(int i=2;i<=n;){
		if(e[1][i]){
			++i;
			continue;
		}
		for(int j=i+1;j<=n;++j)
			if(e[1][j]){
				Xor(i-1,j);
				break;
			}
	}
}

op ans[MAXN*20];

int cnt;

int main(){
	scanf("%d",&n);
	Solve();
	for(int i=0;i<s.size();++i)
		ans[++cnt]=s[i];
	type=1;	 
	Solve();
	for(int i=s.size();i;--i)
		ans[++cnt]=s[i-1];
	printf("%d\n",cnt);
	for(int i=1;i<=cnt;++i)
		printf("%d %d\n",ans[i].fi,ans[i].se); 
	return 0;
}

codechef Random Number Generator

题意:求常系数齐次递推数列的第n项

当递推系数非零项很多的时候暴力复位一次是O(k2)的

构造特征矩阵M的特征多项式f(x)=xk-∑i ci*xi

由f(M)=0,那么我们复位时只需要mod f(x)就好

Portal

#include <stdio.h>
#include <string.h>
#include <algorithm>

#define g() getchar()
template<class Q>void Scan(Q&x){
	char c; while(c=g(),c<48||c>57);
	for(x=0;c>47&&c<58;c=g())x=10*x+c-48;
}

#define G 3
#define maxn 65536
#define DFT(a,n) fft(a,n,0)
#define IDFT(a,n) fft(a,n,1)
#define INV(x) qpow(x,P-2)
#define rep(i,a,b) for(int i=a;i<(b);++i)

using namespace std;

const int MAXN=(1<<16)+5;
const int P=104857601;
typedef long long ll;

inline ll qpow(ll x,int k){
	ll ans=1;
	for(;k;x=x*x%P,k>>=1)
		if(k&1)ans=ans*x%P;
	return ans;
}

int r[MAXN],w[2][MAXN],rn;

inline void init_fft(int n,int b){	
	rn=INV(n);
	rep(i,1,n){
		r[i]=(r[i>>1]>>1)|((i&1)<<(b-1));
	}
}

inline void fft(int*a,int n,int t){
	rep(i,1,n)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=2;i<=n;i<<=1)
		for(int j=0;j<n;j+=i)
			for(int k=0;k<i>>1;++k){
				int re=1ll*a[(i>>1)+j+k]*w[t][maxn/i*k]%P;
				a[(i>>1)+j+k]=(a[j+k]+P-re)%P;
				a[j+k]=(a[j+k]+re)%P;
			}
	if(t)rep(i,0,n)a[i]=1ll*a[i]*rn%P;
}

int k,len,bit;

inline void inv(int*a,int*b){
	static int c[MAXN],l;
	b[0]=1,b[1]=0,l=1;
	rep(j,1,bit+1){
		l<<=1;
		rep(i,0,l)c[i]=a[i];
		rep(i,l,l<<1)b[i]=c[i]=0;
		init_fft(l<<1,j+1);
		
		DFT(b,l<<1),DFT(c,l<<1);
		rep(i,0,l<<1){
			b[i]=1ll*b[i]*(2+P-1ll*b[i]*c[i]%P)%P;
		}
		IDFT(b,l<<1);
		rep(i,l,l<<1)b[i]=0;
	} 
}

int m[MAXN],dm[MAXN],im[MAXN];

int ta[MAXN],ra[MAXN];

inline void mod(int*a){
	DFT(ta,len),DFT(a,len);
	rep(i,0,len)a[i]=1ll*a[i]*ta[i]%P;
	IDFT(a,len); 
	
	rep(i,0,k-1)ra[i]=a[(k-1<<1)-i];
	rep(i,k-1,len)ra[i]=0;
	DFT(ra,len);
	rep(i,0,len)ra[i]=1ll*ra[i]*im[i]%P;
	IDFT(ra,len);

	rep(i,0,k-1)ta[i]=ra[k-2-i];
	rep(i,k-1,len)ta[i]=0;
	DFT(ta,len);
	rep(i,0,len)ta[i]=1ll*ta[i]*dm[i]%P;
	IDFT(ta,len);

	rep(i,0,k)a[i]=(a[i]+P-ta[i])%P;
	rep(i,k,len)a[i]=0;
}

inline void Init(){
	int n=maxn;
	int g=qpow(G,(P-1)/n);
	w[0][0]=w[0][n]=1;
	rep(i,1,n)w[0][i]=1ll*w[0][i-1]*g%P;
	rep(i,0,n+1)w[1][i]=w[0][n-i];
}

ll n;

int a[MAXN],ans[MAXN],x[MAXN];

int main(){
	Init();
	
	Scan(k),Scan(n),--n;
	
	len=k+1,bit=1;
	while(1<<bit<len)++bit;
	len=1<<bit;
	
	rep(i,0,k)Scan(a[i]);
	for(int i=k-1;~i;--i){
		Scan(m[i]),m[i]=(P-m[i])%P;
	}
	
	if(k==1){
		int res=qpow((P-m[0])%P,n%(P-1))*a[0]%P;
		printf("%d\n",res);
		return 0;
	} 
	
	m[k]=1;
	rep(i,0,k+1)dm[i]=m[k-i];
	inv(dm,im);
	
	len<<=1,++bit;
	rep(i,0,k+1)dm[i]=m[i];
	rep(i,k+1,len)dm[i]=im[i]=0;
	DFT(dm,len),DFT(im,len);
	
	for(ans[0]=x[1]=1;n;n>>=1){
		if(n&1){
			rep(i,0,len)ta[i]=x[i]; 
			mod(ans);
		}
		rep(i,0,len)ta[i]=x[i];
		mod(x);
	}
	
	int res=0;
	rep(i,0,k){
		res=(res+1ll*a[i]*ans[i])%P;
	}
	printf("%d\n",res);
	
	return 0;
}

hdu4914 Linear recursive sequence

题意:给出序列f,fn=(n>0)?a*fn-p+b*fn-q:1,求第n项

叉姐论文: k阶矩阵M的任意幂次都能用M小于k次的幂次来线性表示

所以我们构造多项式fn(x),[xi]fn(x)表示用小于k次的幂次线性表示时i次幂前的系数

用多项式乘法+快速幂计算fn(x),每次乘法后溢出k-1次的部分暴力还原

这题 mod 119,中间结果不会太大,所以直接用复数域上的fft,做完一次乘法后再取模就好

Portal

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define DFT(a) fft(a,len,0)
#define IDFT(a) fft(a,len,1)
#define rep(i,a,b) for(int i=a;i<(b);++i)
using namespace std;

const int MAXN=(1<<18)+5; 

typedef double db;
const db Pi=acos(-1.);

typedef long long ll;
const int Mod=119;

struct cp{
	db r,i;
	cp(db r=0,db i=0):r(r),i(i){}
	friend cp operator+(const cp&a,const cp&b){
		return cp(a.r+b.r,a.i+b.i);
	}
	friend cp operator-(const cp&a,const cp&b){
		return cp(a.r-b.r,a.i-b.i);
	}
	friend cp operator*(const cp&a,const cp&b){
		return cp(a.r*b.r-a.i*b.i,a.r*b.i+a.i*b.r);
	}
}w[2][MAXN];

inline cp Exp(db x){
	return cp(cos(x),sin(x));
}

int r[MAXN];

inline void init_fft(int n,int b){
	w[0][0]=w[0][n]=cp(1.,0);
	cp g=Exp(Pi*2./n);
	rep(i,1,n)w[0][i]=w[0][i-1]*g;
	rep(i,0,n+1)w[1][i]=w[0][n-i];
	rep(i,1,n){
		r[i]=(r[i>>1]>>1)|((i&1)<<(b-1));
	}
} 

inline void fft(cp*a,int n,int t){
	rep(i,1,n)if(i<r[i])swap(a[i],a[r[i]]);
	for(int i=2;i<=n;i<<=1)
		for(int j=0;j<n;j+=i)
			for(int k=0;k<i>>1;++k){
				cp re=a[(i>>1)+j+k]*w[t][n/i*k];
				a[(i>>1)+j+k]=a[j+k]-re;
				a[j+k]=a[j+k]+re;
			} 
	if(t)rep(i,0,n)a[i].r/=n;
}

cp ta[MAXN],tb[MAXN];

int n,A,B,p,q,len,bit;

struct poly{
	int a[MAXN];
	inline void mul(const poly&o){
		rep(i,0,q)ta[i]=cp(a[i]),tb[i]=cp(o.a[i]);
		rep(i,q,len)ta[i]=tb[i]=cp();
		DFT(ta),DFT(tb);
		rep(i,0,len)ta[i]=ta[i]*tb[i];
		IDFT(ta);
		rep(i,0,len)a[i]=ll(ta[i].r+0.5)%Mod;
		for(int i=len;i>=q;--i)if(a[i]){
			a[i-p]=(a[i-p]+a[i]*A%Mod)%Mod;
			a[i-q]=(a[i-q]+a[i]*B%Mod)%Mod;
		}
	}
}a,b;

inline void qpow(poly&ans,poly&x,int k){
	rep(i,0,len)ans.a[i]=x.a[i]=0;
	ans.a[0]=x.a[1]=1;
	for(;k;x.mul(x),k>>=1)
		if(k&1)ans.mul(x);
}

int f[MAXN];

inline int F(int x){return x>0?f[x]:1;}

int main(){
	while(~scanf("%d%d%d%d%d",&n,&A,&B,&p,&q)){
		A%=Mod,B%=Mod;
		rep(i,1,q<<1|1){
			f[i]=(F(i-p)*A+F(i-q)*B)%Mod; 
		}
		if(n<=(q<<1)){
			printf("%d\n",f[n]);
			continue;
		}
		len=q<<1|1,bit=1;
		while(1<<bit<len)++bit;
		len=1<<bit;
		init_fft(len,bit);
		qpow(a,b,n-q);
		int ans=0;
		for(int i=q-1;~i;--i){
			ans=(ans+a.a[i]*f[i+q])%Mod;
		}
		printf("%d\n",ans);
	}
	return 0;
}