20200529小結(上)

七彩樹

題意:n個節點的樹,每個點有一個顏色,詢問點u子樹中距離不超過d的節點有多少種不同的顏色

題解:按深度依次插入節點u,用set維護它dfs序相鄰的同色點l,r,

再對每一個深度開一個動態開點線段樹,把u對應的dfs序位置 u+1,LCA(u,l)-1,LCA(u,r)-1,LCA(l,r)+1

實際上就是一個lca去重,查詢的時候直接查dep[u]+d對應深度的線段樹中u子樹對應的區間

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
#define N 100005
int col[N],fir[N],to[2*N],nxt[2*N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int fa[N],son[N],top[N],siz[N],dep[N],dfn[N],num[N],dc;
vector<int> G[N];int mxd;
void dfs1(int u)
{
	dep[u]=dep[fa[u]]+1;siz[u]=1;
	mxd=max(mxd,dep[u]);
	G[dep[u]].push_back(u);
	for(int v,p=fir[u];p;p=nxt[p]){
		if((v=to[p])!=fa[u]){
			fa[v]=u;dfs1(v);
			siz[u]+=siz[v];
			if(siz[son[u]]<siz[v])
				son[u]=v;
		}
	}
}
void dfs2(int u)
{
	dfn[u]=++dc;num[dc]=u;
	if(son[u])top[son[u]]=top[u],dfs2(son[u]);
	for(int v,p=fir[u];p;p=nxt[p])
		if((v=to[p])!=fa[u]&&v!=son[u])
			top[v]=v,dfs2(v);
}
int LCA(int x,int y)
{
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
set<int> S[N];
set<int>::iterator it1,it2,edi;
struct node{
	int l,r,x;
}a[N<<5];
int T[N],tot;
void insert(int &i,int l,int r,int x,int k,int pre)
{
	if(i==pre)i=++tot,a[i]=a[pre];
	a[i].x+=k;
	if(l==r)return;
	int mid=(l+r)>>1;
	if(x<=mid)insert(a[i].l,l,mid,x,k,a[pre].l);
	else insert(a[i].r,mid+1,r,x,k,a[pre].r);
}
int query(int i,int l,int r,int ql,int qr)
{
	if(ql>r||l>qr)return 0;
	if(ql<=l&&r<=qr)return a[i].x;
	int mid=(l+r)>>1;
	return query(a[i].l,l,mid,ql,qr)+query(a[i].r,mid+1,r,ql,qr);
}
int main()
{
	int Tes,i,j,n,m,u,l,r,d;
	scanf("%d",&Tes);
	while(Tes--){
		scanf("%d%d",&n,&m);
		for(i=1;i<=n;i++)scanf("%d",&col[i]);
		for(i=2;i<=n;i++){scanf("%d",&u);adde(u,i);}
		dc=mxd=0;
		dfs1(1);top[1]=1;dfs2(1);
		for(i=1;i<=mxd;i++){
			T[i]=T[i-1];
			for(j=0;j<int(G[i].size());j++){
				u=G[i][j];l=r=0;
				it1=it2=S[col[u]].lower_bound(dfn[u]);
				if(it1!=S[col[u]].begin())it1--,l=num[*it1];
				edi=S[col[u]].end();
				if(it2!=edi)r=num[*it2];
				
				insert(T[i],1,dc,dfn[u],1,T[i-1]);
				if(l)
					insert(T[i],1,dc,dfn[LCA(u,l)],-1,T[i-1]);
				if(r)
					insert(T[i],1,dc,dfn[LCA(u,r)],-1,T[i-1]);
				if(l&&r)
					insert(T[i],1,dc,dfn[LCA(l,r)],1,T[i-1]);
				S[col[u]].insert(dfn[u]);
			}
		}
		int las=0;
		for(i=1;i<=m;i++){
			scanf("%d%d",&u,&d);
			u^=las;d^=las;
			int nd=min(mxd,d+dep[u]);
			las=query(T[nd],1,dc,dfn[u],dfn[u]+siz[u]-1);
			printf("%d\n",las);
		}
		
		cnt=0;tot=0;
		for(i=1;i<=n;i++){
			fir[i]=0;
			S[col[i]].clear();
			dfn[i]=num[i]=0;
			siz[i]=fa[i]=son[i]=top[i]=dep[i]=0;
		}
		for(i=1;i<=mxd;i++)G[i].clear(),T[i]=0;
	}
}

 

Prime Distance On Tree

題意:一棵n個點的樹,求選出任意兩點,其距離爲質數的概率

題解:點分治+FFT版題,子樹去重一下即可

代碼:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
int n;
int prime[N],tot;
bool pvis[N];
void shai()
{
	int i,j;pvis[1]=1;
	for(i=2;i<=n;i++){
		if(!pvis[i])prime[++tot]=i;
		for(j=1;j<=tot;j++){
			int tmp=i*prime[j];
			if(tmp>n)break;
			pvis[tmp]=1;
			if(i%prime[j]==0)break;
		}
	}
}
int fir[N],to[2*N],nxt[2*N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int tmpsiz[N],nrt,all;
bool vis[N];
void findrt(int u,int ff)
{
	tmpsiz[u]=1;int mx=0;
	for(int v,p=fir[u];p;p=nxt[p]){
		if((v=to[p])!=ff&&!vis[v]){
			findrt(v,u);
			tmpsiz[u]+=tmpsiz[v];
			mx=max(mx,tmpsiz[v]);
		}
	}
	mx=max(mx,all-tmpsiz[u]);
	if(2*mx<=all)nrt=u;
}
int getrt(int u,int sz)
{
	all=sz;nrt=-0x3f3f3f3f;
	findrt(u,0);return nrt;
}
struct cp{
	double r,i;
	cp(){}
	cp(double x,double y){r=x;i=y;}
	cp operator + (const cp &t){return cp(r+t.r,i+t.i);}
	cp operator - (const cp &t){return cp(r-t.r,i-t.i);}
	cp operator * (const cp &t){return cp(r*t.r-i*t.i,r*t.i+i*t.r);}
}w,wn;
int rev[N];
const double PI=3.14159265358979323846264338;
void FFT(vector<cp> &a,int len,int flg)
{
	int i,j,k;
	for(i=0;i<len;i++)rev[i]=(rev[i>>1]>>1)|((i&1)*(len>>1));
	for(i=0;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(i=1;i<len;i<<=1){
		wn=cp(cos(PI/i),sin(PI/i));
		if(flg==-1)wn.i=-wn.i;
		for(j=0;j<len;j+=(i<<1)){
			w=cp(1,0);
			for(k=j;k<i+j;k++){
				cp u=a[k],v=a[k+i]*w;
				a[k]=u+v;
				a[k+i]=u-v;
				w=w*wn;
			}
		}
	}
	if(flg==-1)
		for(i=0;i<len;i++)
			a[i].r/=len;
}
vector<cp> a,c;
void pre(int u,int ff,int d)
{
	tmpsiz[u]=1;
	while(d>=(int)a.size())a.push_back(cp(0,0));
	a[d].r++;
	for(int v,p=fir[u];p;p=nxt[p]){
		if(!vis[v=to[p]]&&v!=ff){
			pre(v,u,d+1);
			tmpsiz[u]+=tmpsiz[v];
		}
	}
}
long long ans;
void update(vector<cp> &a,int flg)
{
	c.clear();int len=1;
	while(len<2*(int)a.size())len<<=1;
	while((int)a.size()<len)a.push_back(cp(0,0));
	while((int)c.size()<len)c.push_back(cp(0,0));
	FFT(a,len,1);
	for(int i=0;i<len;i++)c[i]=a[i]*a[i];
	FFT(c,len,-1);
	for(int i=2;i<len;i++)if(!pvis[i])
		ans=ans+1ll*flg*(long long)(c[i].r+0.5);
}
void DFZ(int u)
{
	vis[u]=1;
	a.clear();pre(u,0,0);
	update(a,1);
	for(int v,p=fir[u];p;p=nxt[p])
		if(!vis[v=to[p]]){
			a.clear();pre(v,u,1);
			update(a,-1);
		}
	for(int v,p=fir[u];p;p=nxt[p])
		if(!vis[v=to[p]])DFZ(getrt(v,tmpsiz[v]));
}
int main()
{
	//freopen("1.in","r",stdin);
	//freopen("WA.out","w",stdout);
	int i,u,v;
	n=gi();shai();
	for(i=1;i<n;i++){u=gi();v=gi();adde(u,v);}
	DFZ(getrt(1,n));
	ans/=2;
	printf("%.6f\n",(double)ans/((long long)n*(n-1)/2));
}

 

Can Bash Save the Day?

題意:給一個n個點的樹與一個長度爲n的排列a,每次修改交換排列上相鄰的兩個數, 每次詢問給出l,r,v,求al~ar每個點到v的距離和

題解:可持久化點分樹

像之前那道題一樣做的話時間空間都是無法承受的

考慮到如果可以維護出a1~ai的點分樹(每個點分中心維護a的前綴點集到它的距離和以及它點分區域包含點的個數)

那麼我們可以直接差分得到答案了

於是,可持久化點分樹就誕生了,每次加入一個點就對應修改點分樹上的一條鏈

但是事與願違,我們對於每個點分中心還要保存它兒子的信息來去重,而如果是菊花圖就會把可持久化點分樹卡到n^2

所以我們還需要把原樹進行三度化

代碼:(細節過多引起極度不適)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 400005
int n,m,P[N];
int fir[N],to[2*N],nxt[2*N],cd[2*N],cnt,du[N];
void adde(int a,int b,int c)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;cd[cnt]=c;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;cd[cnt]=c;
	du[a]++;du[b]++;
}
struct node{
	int u,v,w;
	node(){}
	node(int x,int y,int z){u=x;v=y;w=z;}
}e[N];int ecnt;
void sandu(int u,int ff)
{
	int pre=u;
	for(int v,p=fir[u];p;p=nxt[p]){
		v=to[p];if(v==ff)continue;
		if(du[u]-bool(ff)>=3){
			e[++ecnt]=node(pre,++n,0);
			e[++ecnt]=node(n,v,cd[p]);
			pre=n;
		}
		else e[++ecnt]=node(u,v,cd[p]);
		sandu(v,u);
	}
}
bool vis[N];
int tmpsiz[N],all,nrt;
void findrt(int u,int ff)
{
	tmpsiz[u]=1;int mx=0;
	for(int v,p=fir[u];p;p=nxt[p]){
		if((v=to[p])!=ff&&!vis[v]){
			findrt(v,u);
			tmpsiz[u]+=tmpsiz[v];
			mx=max(mx,tmpsiz[v]);
		}
	}
	mx=max(mx,all-tmpsiz[u]);
	if(2*mx<=all)nrt=u;
}
int getrt(int u,int sz)
{
	all=sz;nrt=-0x3f3f3f3f;
	findrt(u,0);return nrt;
}
#define LOG 20
#define LL long long
LL dis[LOG][N];int from[LOG][N],dep[N];
int id[N*LOG],ch[N*LOG][4],T[N],tot;
LL sum[N*LOG],fsum[N*LOG],con[N*LOG];
void pre(int u,int ff,int d)
{
	tmpsiz[u]=1;
	for(int v,p=fir[u];p;p=nxt[p]){
		if(!vis[v=to[p]]&&v!=ff){
			dis[d][v]=dis[d][u]+1ll*cd[p];
			pre(v,u,d);
			tmpsiz[u]+=tmpsiz[v];
		}
	}
}
void DFZ(int u,int d)
{
	dep[u]=d;id[u]=u;
	vis[u]=1;pre(u,0,d);
	for(int v,p=fir[u],so=0;p;p=nxt[p]){
		if(!vis[v=to[p]]){
			v=getrt(v,tmpsiz[v]);
			ch[u][so]=v;from[d][v]=so;so++;
			for(int i=0;i<d;i++)
				from[i][v]=from[i][u];
			DFZ(v,d+1);
		}
	}
}
void insert(int &u,int x)
{
	id[++tot]=id[u];sum[tot]=sum[u];fsum[tot]=fsum[u];con[tot]=con[u];
	for(int i=0;i<=2;i++)ch[tot][i]=ch[u][i];u=tot;
	int d=dep[id[u]];
	sum[u]+=dis[d][x];con[u]++;
	if(d)fsum[u]+=dis[d-1][x];
	if(id[u]==x)return;
	insert(ch[u][from[d][x]],x);
}
LL query(int u,int x)
{
	if(!u)return 0ll;
	LL ret=sum[u]+con[u]*dis[0][x];
	for(int i=1;i<=dep[x];i++){
		u=ch[u][from[i-1][x]];
		ret+=sum[u]+con[u]*dis[i][x];
		ret-=fsum[u]+con[u]*dis[i-1][x];
	}
	return ret;
}
int main()
{
	int u,v,w,i,tn,op,l,r,x;
	tn=n=gi();m=gi();
	for(i=1;i<=n;i++)P[i]=gi();
	for(i=1;i<n;i++){u=gi();v=gi();w=gi();adde(u,v,w);}
	sandu(1,0);
	cnt=0;memset(fir,0,sizeof(fir));
	for(i=1;i<=ecnt;i++)adde(e[i].u,e[i].v,e[i].w);
	DFZ(T[0]=getrt(1,n),0);tot=n;
	for(i=1;i<=tn;i++)
		insert(T[i]=T[i-1],P[i]);
	LL ans=0;
	for(i=1;i<=m;i++){
		op=gi();
		if(op==1){
			l=gi();r=gi();x=gi();
			l^=ans;r^=ans;x^=ans;
			ans=query(T[r],x)-query(T[l-1],x);
			printf("%lld\n",ans);
			ans=ans%(1<<30);
		}
		else{
			x=gi();x^=ans;
			swap(P[x],P[x+1]);
			insert(T[x]=T[x-1],P[x]);
		}
	}
}

 

 

[JZOJ5520]Every one will meet some difficult

https://blog.csdn.net/hzj1054689699/article/details/85857283

考慮組合意義,利用生成函數將式子化爲卷積形式,再暴力卷積+快速冪即可

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1005
#define LL long long
const int mod=1000109107;
int lim;
struct node{
	int a[N];
	node(){memset(a,0,sizeof(a));}
	node operator * (const node &t)const{
		node c;
		for(int i=0;i<lim;i++)
			for(int j=0;i+j<lim;j++)
				c.a[i+j]=(c.a[i+j]+1ll*a[i]*t.a[j])%mod;
		return c;
	}
	node operator ^ (LL y)const{
		node ret,x=*this;ret.a[0]=1;
		while(y){
			if(y&1)ret=ret*x;
			y>>=1;x=x*x;
		}
		return ret;
	}
}a,b;
int main()
{
	int i,j;LL s,t,n,m;
	scanf("%lld%lld%lld%lld",&s,&t,&n,&m);
	lim=m-n+2;
	a.a[0]=a.a[1]=b.a[0]=b.a[1]=1;
	a=a^t;b=b^(s-n*t);
	for(i=0;i<lim;i++)a.a[i]=a.a[i+1];
	a=a^n;a=a*b;
	printf("%d",a.a[m-n]);
}

 

 

 

20200518魚貫而入

題意:給出n個數,求一個hash表的大小len,使這n個數撞hash的次數最多,輸出撞hash的次數。

(這裏的hash表是:如果y=x%len撞了hash,那麼就把y放到y+1位置(如果繼續撞就再+1))

n<=200

題解:亂搞題

先暴力驗證一下小範圍的len,再n個數任選兩個做差,驗證一下差的所有因子

這裏的差可能比較大,PR一下即可

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define N 205
#define LL long long

int nn,ans;LL a[N];
map<LL,LL> h;
void add_fish(int &cnt,LL x,LL len)
{
	LL y=x%len;
	while(h.count(y)&&h[y]!=x)y=(y+1)%len,cnt++;
    h[y]=x;
}
//#include<ctime>
//double sum;
void solve(LL len)
{
	//double c1=clock();
	h.clear();int cnt=0,i;
	for(i=1;i<=nn;i++) add_fish(cnt,a[i],len);
	//if(cnt>ans)printf("%lld\n",len);
	ans=max(cnt,ans);
	//sum+=clock()-c1;
}

inline LL mul(LL a,LL b,LL p){return (a*b-(LL)((long double)a*b/p)*p+p)%p;}
LL ksm(LL x,LL y,LL mod)
{
	LL ans=1;
	while(y){
		if(y&1) ans=mul(ans,x,mod);
		y>>=1;x=mul(x,x,mod);
	}
	return ans;
}
bool MR(LL n)
{
	if(n==2) return 1;
	if(n<2||!(n&1)) return 0;
	LL m=n-1;int i,j,k=0;
	while(!(m&1)){k++;m>>=1;}
	for(i=0;i<10;i++){
		LL a=rand()%(n-1)+1,x=ksm(a,m,n),y=0;
		for(j=0;j<k;j++){
			y=mul(x,x,n);
			if(y==1&&x!=1&&x!=n-1) return 0;
			x=y;
		}
		if(y!=1) return 0;
	}
	return 1;
}
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
LL Rho(LL n,LL c)
{
    LL x=rand()%n+1,y=x,q=1,d=1,k=1;
	while(1){
        for(int i=1;i<=k;i++){
            x=(mul(x,x,n)+c)%n;
            q=mul(q,abs(x-y),n);
            if(!(i&127)&&(d=gcd(q,n))>1) break;
        }
        if(d>1||(d=gcd(q,n))>1)
			return d==n?Rho(n,c+1):d;
		k<<=1;q=1;y=x;
    }
}
//int con;
void Pollar(LL n)
{
    if(n==1) return;
    if(MR(n)){if(n>2000)solve(n);return;}
    LL p=Rho(n,3);
    while(n%p==0) n/=p;
    Pollar(p);Pollar(n);
}

int main()
{
	//freopen("3.in","r",stdin);
	//double c1=clock();
	srand(0);
	int tp,i,j;
	scanf("%d%d",&tp,&nn);
	for(i=1;i<=nn;i++)scanf("%lld",&a[i]);
	for(i=nn;i<=2000;i++)solve(i);
	sort(a+1,a+nn+1);
	for(i=2;i<=nn;i++){
		int tt=min(i-1,10);
		while(tt--){
			j=rand()%(i-1)+1;
			Pollar(a[i]-a[j]);
		}
	}
	//printf("%d\n",con);
	//printf("%.3f\n",sum/1000);
	printf("%d\n",ans);
	//printf("%.3fs\n",(clock()-c1)/1000);
}

 

 

 

小P的畫

論文題

過於毒瘤,題解咕咕咕了

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N (1<<15)+1
#define LL long long
const int mod=998244353;
int con[N],lg[N],pw3[16];LL pw2[61];
int w[N],g[N],st[N],f[14348907];bool pd[N];
LL a[16];int rk[16],id[16];
bool cmp(int x,int y){return a[x]<a[y];}

int cnt;LL ta[N];int dp[2][2];
int solve(LL C)
{
	if(C>ta[cnt]&&(C^ta[cnt])>ta[cnt])return 0;
	if(ta[cnt]==0)return 1;
	LL X=1ll<<(upper_bound(pw2,pw2+60,ta[cnt])-pw2-1);
	dp[0][0]=dp[0][1]=dp[1][0]=dp[1][1]=0;
	int now=0;
	dp[now][0]=1;
	for(int i=1;i<cnt;i++){
		dp[now^1][0]=dp[now^1][1]=0;
		if(ta[i]>=X){
			dp[now^1][0]=(1ll*X%mod*dp[now][0]+1ll*(ta[i]-X+1)%mod*dp[now][1])%mod;
			dp[now^1][1]=(1ll*X%mod*dp[now][1]+1ll*(ta[i]-X+1)%mod*dp[now][0])%mod;
		}
		else{
			dp[now^1][0]=1ll*(ta[i]+1)%mod*dp[now][0]%mod;
			dp[now^1][1]=1ll*(ta[i]+1)%mod*dp[now][1]%mod;
		}
		now^=1;
	}
	int ret;
	if(C>=X)ret=dp[now][1];
	else ret=dp[now][0];
	ta[cnt]^=X;C^=X;
	for(int i=cnt;i>1;i--){
		if(ta[i]<ta[i-1])swap(ta[i],ta[i-1]);
		else break;
	}
	return (ret+solve(C))%mod;
}
bool e[16][16];
int main()
{
	int n,m,all,al3,i,s,t,u,v;LL C;
	scanf("%d%d%lld",&n,&m,&C);
	
	all=1<<n;
	for(i=0;i<n;i++)scanf("%lld",&a[i]),id[i]=i;
	sort(id,id+n,cmp);sort(a,a+n);
	for(i=0;i<n;i++)rk[id[i]]=i;
	lg[0]=-1;
	for(s=1;s<all;s++){
		lg[s]=lg[s>>1]+1;
		con[s]=con[s>>1]+(s&1);
	}
	pw2[0]=1;pw3[0]=1;
	for(i=1;i<=60;i++)pw2[i]=2ll*pw2[i-1];
	for(i=1;i<=n;i++)pw3[i]=3*pw3[i-1];
	al3=pw3[n];
	
	for(i=1;i<=m;i++){
		scanf("%d%d",&u,&v);
		if(u>v)swap(u,v);e[u][v]=1;
		u=rk[u-1];v=rk[v-1];
		pd[(1<<u)|(1<<v)]=1;
	}
	for(i=0;i<n;i++)for(s=0;s<all;s++)
		if(s&(1<<i))pd[s]|=pd[s^(1<<i)];
	
	for(s=1;s<all;s++){
		w[s]=!pd[s];// \sum_{i=0}^{Ecnt[s]} C(Ecnt[s],i)*(-1)^i=0^(Ecnt[s])
		for(t=(s-1)&s;t;t=(t-1)&s)if(t&(s&-s))
			w[s]=(w[s]-w[t]*(!pd[s^t]))%mod;
	}
	for(s=1;s<all;s++)if(!(con[s]&1))w[s]=1ll*(a[lg[s&-s]]+1)%mod*w[s]%mod;
	
	for(s=1;s<all;s++){
		cnt=0;
		for(i=0;i<n;i++)if(s&(1<<i))
			ta[++cnt]=a[i];
		g[s]=solve(C);
	}
	
	for(s=1;s<all;s++)st[s]=st[s>>1]*3+(s&1);
	for(s=1;s<all;s++)if(con[s]&1)st[s]+=pw3[lg[s&-s]];
	f[0]=1;if(C==0)g[0]=1;
	int ans=0;
	for(s=0;s<al3;s++)if(f[s]){
		int flg=0,s0=0;
		for(i=0;i<n;i++)if(s/pw3[i]%3==0)s0|=1<<i;
		if(s0){
			flg=(s0&-s0);s0-=flg;
			for(t=s0;;t=(t-1)&s0){
				int tmp=s+st[t+flg];
				f[tmp]=(1ll*f[tmp]+1ll*f[s]*w[t+flg])%mod;
				if(!t)break;
			}
		}
		else{
			int s2=0;
			for(i=0;i<n;i++)if(s/pw3[i]%3==2)s2|=1<<i;
			ans=(1ll*ans+1ll*f[s]*g[s2])%mod;
		}
	}
	printf("%d\n",(ans+mod)%mod);
}

 

 

 

20200521river

n<=10^9,m<=10^6

題解:貪心

先求出每種天氣下到達下一個地點的最少天數,我們一定是每次都選擇最少天數的方法去走

於是我們可以建出一個有向圖,且帶有一個環,跟Pollard_Rho中的Rho很像的

先算一下環外鏈的權值,再算一下環的權值

我們如果走完了環外了鏈,就會到環上轉圈圈

環權值乘上我們轉的圈數就是我們轉圈的代價,如果還沒有到達目的地,就再手動把剩下的幾步加上

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 1000005
#define LL long long
const LL INF=0x3f3f3f3f3f3f3f3fll;
int a[N],dfn[N],cnt,fir,len;LL g[N];bool vis[N];
int main()
{
	int n,m,i,j;
	LL pre=INF,suf=INF,ans=0,sum=0;
	n=gi();m=gi();
	for(i=0;i<m;i++)a[i]=gi(),g[i]=INF;
	for(i=1;i<m;i++)pre=min(pre,1ll*a[i-1]+i-1),g[i]=min(g[i],pre+1ll*m-1ll*i);
	for(i=m-1;i>=0;i--)suf=min(suf,1ll*a[i]+i),g[i]=min(g[i],suf-1ll*i);
	for(i=0;!vis[i];i=(i+g[i])%m)
		vis[i]=1,dfn[++cnt]=i;
	fir=i;
	for(i=1;dfn[i]!=fir&&i<=cnt;i++)
		ans+=g[dfn[i]],n--;
	if(n>0){
		for(j=i;j<=cnt;j++)sum+=g[dfn[j]];
		ans+=n/(cnt-i+1)*sum;n%=(cnt-i+1);
		for(j=i;n;j++,n--)ans+=g[dfn[j]];
	}
	printf("%lld\n",ans);
}

 

 

20200521cac

 

題解:圓方樹+樹狀數組,把方點與圓點的貢獻分開來計算,方點用樹狀數組統計,圓點就直接加權值

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 600005
#define M 1000005
int fir[N],nxt[2*N],to[2*N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
int dfn[N],low[N],stk[N],tp,dc,pbccnt;
vector<int> pbc[N];
void dfs(int u,int fa)
{
	dfn[u]=low[u]=++dc;
	stk[tp++]=u;
	int v,p;
	for(p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(!dfn[v]){
			dfs(v,u);low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]){
				pbccnt++;
				while(tp>0){
					pbc[pbccnt].push_back(stk[--tp]);
					if(stk[tp]==v)
						break;
				}
				pbc[pbccnt].push_back(u);
			}
		}
		else if(v!=fa) low[u]=min(low[u],dfn[v]);
	}
}
int fa[N],dep[N],son[N],siz[N],top[N];
void dfs1(int u)
{
	dep[u]=dep[fa[u]]+1;
	int v,p;siz[u]=1;
	for(p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(v!=fa[u]){
			fa[v]=u;dfs1(v);siz[u]+=siz[v];
			if(siz[son[u]]<siz[v])
				son[u]=v;
		}
	}
}
const int mod=998244353;
int pos[N],ddfn;
void dfs2(int u)
{
	pos[u]=++ddfn;
	if(son[u]) top[son[u]]=top[u],dfs2(son[u]);
	int v,p;
	for(p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(v!=son[u]&&v!=fa[u])
			top[v]=v,dfs2(v);
	}
}
int LCA(int x,int y)
{
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		x=fa[top[x]];
	}
	return dep[x]<dep[y]?x:y;
}
int tra[N];
void update(int x,int k)
{
	if(!x)return;
	while(x<=600000){
		tra[x]=(1ll*tra[x]+1ll*mod+1ll*k)%mod;
		x+=(x&-x);
	}
}
int getsum(int x)
{
	int ret=0;
	while(x){
		ret=(ret+tra[x])%mod;
		x-=(x&-x);
	}
	return ret;
}
int val[N];
int main()
{
	int n,m,Q,i,j,k,u,v,op;
	n=gi();m=gi();Q=gi();
	for(i=1;i<=m;i++){
		u=gi();v=gi();
		adde(u,v);
	}
	for(i=1;i<=n;i++)
		if(!dfn[i])dfs(i,0);
	memset(fir,0,sizeof(fir));cnt=0;
	for(i=1;i<=pbccnt;i++)
		for(j=0,k=pbc[i].size();j<k;j++)
			adde(n+i,pbc[i][j]);
	dfs1(1);top[1]=1;dfs2(1);
	for(i=1;i<=Q;i++){
		op=gi();
		if(!op){
			u=gi();v=gi();k=gi();
			update(pos[fa[u]],k);update(pos[fa[v]],k);
			int lca=LCA(u,v);
			if(lca>n){
				update(pos[lca],-k);(val[fa[lca]]+=k)%=mod;
				lca=fa[lca],update(pos[fa[lca]],-k);
			}
			else{
				update(pos[lca],-2*k%mod);
				(val[lca]+=k)%=mod;
			}
		}
		else{
			u=gi();
			int ans=val[u];
			if(fa[u])u=fa[u],ans=(1ll*ans+1ll*getsum(pos[u]+siz[u]-1)+mod-getsum(pos[u]-1))%mod;
			printf("%d\n",ans);
		}
	}
}

 

 

 

20200522A

題解:組合數——二項式定理——生成函數——等比數列求和

參考:Freopen大佬的博客

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000105
int n,m;
int pw[100],C[N],inv[N];
void exgcd(int a,int b,int &x,int &y)
{
	if(!b){x=1,y=0;return;}
	exgcd(b,a%b,y,x);
	y-=(a/b)*x;
}
int cmod,cans;
void CRT(int ans,int mod)
{
	int t1,t2;
	exgcd(cmod,mod,t1,t2);
	int A=cmod*mod;
	cans=(1ll*cmod*t1%A*(ans-cans)+cans)%A;
	cmod=A;
}
int solve(int p,int e,int mod)//  calculate the answer mod p^e
{
	int c=1,cnte=0,i,tmp;
	inv[0]=inv[1]=1;
	for(i=2;i<max(3,min(mod,m+2));i++)
		exgcd(i,mod,inv[i],tmp);
	for(i=1;i<=m+1;i++){
		int x=n-i+1,y=i;
		if(x)for(;x%p==0;x/=p,cnte++);
		for(;y%p==0;y/=p,cnte--);
		c=1ll*c*x%mod*inv[y%mod]%mod;
		if(cnte>=e)C[i]=0;
		else C[i]=1ll*c*pw[cnte]%mod;
	}
	int b=0,ret=0;
	for(i=0;i<=m;i++){
		b=1ll*(C[i+1]-b)*inv[2]%mod;
		if(!(i&1)) ret=(ret+b)%mod;
	}
	return ret;
}
int solve2(int e,int mod)//answer mod 2^e
{
	int c=1,cnte=0,i,tmp;
	inv[0]=inv[1]=1;
	for(i=2;i<=m+2+e;i++)
		exgcd(i,mod,inv[i],tmp);
	for(i=1;i<=m+2+e;i++){
		int x=n-i+1,y=i;
		if(x)for(;!(x&1);x>>=1)cnte++;
		for(;!(y&1);y>>=1)cnte--;
		c=1ll*c*x%mod*inv[y%mod]%mod;
		if(cnte>=e)C[i]=0;
		else C[i]=((1ll*c)<<cnte)%mod;
	}
	int b=0;
	for(i=m+1+e;i>=m+2;i--)
		b=(1ll*C[i]-2ll*b)%mod;
	int ret=b;
	for(i=m-1;i>=0;i--){
		b=(1ll*C[i+2]-2ll*b)%mod;
		if(!(i&1)) ret=(ret+b)%mod;
	}
	return ret;
}
int main()
{
	int i,mod;
	scanf("%d%d%d",&n,&m,&mod);
	n+=2;if(n&1)n--;if(m&1)m--;
	int cnte2=0;
	for(;!(mod&1);mod>>=1,cnte2++);
	//1000000000 1000000 536870912
	cans=0;cmod=pw[0]=1;
	for(i=3;i*i<=mod;i++){
		if(mod%i==0){
			int cnt=0;
			while(mod%i==0){
				mod/=i;cnt++;
				pw[cnt]=pw[cnt-1]*i;
			}
			CRT(solve(i,cnt,pw[cnt]),pw[cnt]);
		}
	}
	if(mod>1)CRT(solve(mod,1,mod),mod);
	mod=1<<cnte2;
	CRT(solve2(cnte2,mod),mod);
	printf("%d\n",(cans%cmod+cmod)%cmod);
}

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章