省選模擬賽Round1Day2 旅遊 寶石([CTS2019]珍珠) 線段([APIO2019]路燈)

 

拆開高斯函數後,動態開點線段樹優化DP

啊啊啊啊爲什麼只有50分

淦,沒有把線段樹的mx值賦成-INF。。。

代碼:

#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 222222
#define LOG 30
#define LL long long
const LL INF=0x3f3f3f3f3f3f3f3fll;
int c[N],x,y,z,A,m[N];
LL f[N];
struct node{
	int l,r;LL x;
}a[N*LOG];
int rt,tot;
void insert(int &i,int l,int r,int x,LL k)
{
	if(!i)i=++tot,a[i].x=-INF;
	a[i].x=max(a[i].x,k);
	if(l==r)return;
	int mid=(l+r)>>1;
	if(x<=mid)insert(a[i].l,l,mid,x,k);
	else insert(a[i].r,mid+1,r,x,k);
}
LL query(int i,int l,int r,int ql,int qr)
{
	if(!i||l>qr||r<ql)return -INF;
	if(ql<=l&&r<=qr)return a[i].x;
	int mid=(l+r)>>1;
	return max(query(a[i].l,l,mid,ql,qr),query(a[i].r,mid+1,r,ql,qr));
}
struct anode{
	int c,m;
	bool operator == (const anode &t)const{
		return c==t.c;
	}
}tmp[N];
int main()
{
	freopen("tourist.in","r",stdin);
	freopen("tourist.out","w",stdout);
	int n,i;
	x=gi();y=gi();z=gi();A=gi();n=gi();
	tmp[1].c=x;tmp[n+2].c=y;
	for(i=2;i<=n+1;i++){tmp[i].c=gi();tmp[i].m=gi();}
	n=n+2;
	if(tmp[n]==tmp[n-1])n--;
	if(tmp[1]==tmp[2]){for(i=1;i<n;i++)tmp[i]=tmp[i+1];n--;}
	
	for(i=1;i<=n;i++){c[i]=tmp[i].c;m[i]=tmp[i].m;}
	f[1]=m[1];insert(rt,0,z-1,c[1]%z,f[1]+1ll*c[1]/z*A);
	for(i=2;i<=n;i++){
		f[i]=max((c[i]%z?query(rt,0,z-1,0,c[i]%z-1)-1ll*A:-INF),query(rt,0,z-1,c[i]%z,z-1))-1ll*c[i]/z*A+1ll*m[i];
		insert(rt,0,z-1,c[i]%z,f[i]+1ll*c[i]/z*A);
	}
	printf("%lld\n",f[n]);
}

 

 

題解:生成函數

每個珠子都要選擇一種顏色,當一種顏色的珠子有k個時,這種顏色就可以貢獻floor(k/2)個袋子

設有A種顏色擁有奇數顆珠子,這些珠子的個數爲x

那麼總袋子數就爲(n-x)/2+(x-A)/2>=m

化一下可得n-2*m>=A  (A<=D)

一種顏色有奇數k顆珠子選擇它的方案數爲C(n,k)=n!/(k!*(n-k)!)

我們選擇指數型生成函數來解決這個問題

(這個問題本質上就是把每個珠子分配一種顏色,再將相同顏色的去重,其實就是可重集的全排列)

那麼一種顏色的指數生成函數就是e^x

一種只有奇數個球的顏色的指數生成函數就是\frac{e^x-e^{-x}}{2}

 

代碼:(注意一下二項式反演的部分)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 300005
const int mod=998244353;
const int inv2=499122177;
int fac[N],finv[N];
int wl,wn[N],rev[N];
int ksm(int x,int y)
{
	int ret=1;x=(x%mod+mod)%mod;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		y>>=1;x=1ll*x*x%mod;
	}
	return ret;
}
void shai()
{
	int i,n=100000;
	fac[0]=fac[1]=finv[0]=finv[1]=1;
	for(i=2;i<=n;i++)fac[i]=1ll*fac[i-1]*i%mod;
	finv[n]=ksm(fac[n],mod-2);
	for(i=n;i>=1;i--)finv[i-1]=1ll*finv[i]*i%mod;
	wl=1<<18;wn[0]=1;wn[1]=ksm(3,(mod-1)/wl);
	for(i=2;i<=wl;i++)wn[i]=1ll*wn[i-1]*wn[1]%mod;
}
int C(int x,int y)
{
	return 1ll*fac[x]*finv[y]%mod*finv[x-y]%mod;
}
void NTT(int a[],int len,int flg)
{
	for(int i=1;i<len;i++)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int i=1,x=wl>>1;i<len;i<<=1,x>>=1)for(int j=0;j<len;j+=(i<<1))
		for(int k=j,y=0;k<i+j;k++,y+=x){
			int tmp=1ll*a[k+i]*wn[flg==1?y:wl-y]%mod;
			a[k+i]=(a[k]+mod-tmp)%mod;a[k]=(a[k]+tmp)%mod;
		}
	if(flg==-1)for(int i=0,ni=ksm(len,mod-2);i<len;i++)a[i]=1ll*a[i]*ni%mod;
}
int A[N],B[N];
int main()
{
	freopen("jewel.in","r",stdin);
	freopen("jewel.out","w",stdout);
	int D,n,m,i;shai();
	scanf("%d%d%d",&D,&n,&m);
	for(i=0;i<=D;i++){
		A[i]=1ll*ksm(D-2*i,n)*finv[i]%mod;
		if(i&1)A[i]=(mod-A[i])%mod;
	}
	for(i=0;i<=D;i++)B[i]=finv[i];
	int len=1;while(len<=2*D)len<<=1;
	for(i=1;i<len;i++)rev[i]=(rev[i>>1]>>1)|(i&1?len>>1:0);
	NTT(A,len,1);NTT(B,len,1);
	for(i=0;i<len;i++)A[i]=1ll*A[i]*B[i]%mod;
	NTT(A,len,-1);
	for(i=0;i<=D;i++)A[i]=1ll*A[i]*fac[i]%mod*ksm(inv2,i)%mod*C(D,i)%mod;
	for(i=D+1;i<len;i++)A[i]=B[i]=0;
	for(i=0;i<=D;i++)B[i]=1ll*((D-i)&1?mod-1:1)*finv[D-i]%mod,A[i]=1ll*A[i]*fac[i]%mod;
	NTT(A,len,1);NTT(B,len,1);
	for(i=0;i<len;i++)A[i]=1ll*A[i]*B[i]%mod;
	NTT(A,len,-1);
	int ans=0;
	for(i=0;i<=n-2*m&&i<=D;i++)
		ans=(ans+1ll*A[D+i]*finv[i])%mod;
	printf("%d",ans);
}

 

 

 

 

 

題解:

分別考慮每一段1[l,r]的貢獻(用set來維護連續段)

它可以使所有滿足l<=a<=b<=r的[a,b]都加上它的存在時間(在它結束(分被裂或者合併)的時候統計)

把詢問看作2維上的一個點

轉爲動態二維數點後CDQ分治+靜態二維數點即可

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
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 300005
#define LL long long
set<int> S;
set<int>::iterator it1,it2;
struct node{
	int x,y,v,t,id;
	node(){}
	node(int a,int b,int c,int d,int e){x=a;y=b;v=c;t=d;id=e;}
	bool operator < (const node &T)const{
		return x<T.x||(x==T.x&&t<T.t);
	}
}q[4*N],tmp[4*N];
int acnt,cnt;
int n,Q,las[N];bool vis[N];char ss[N],op[10];
LL ans[N],tra[N];
void update(int x,int k)
{
	x=n-x+1;
	while(x<=n+2){
		tra[x]+=k;
		x+=(x&-x);
	}
}
LL query(int x)
{
	x=n-x+1;
	LL ret=0;
	while(x){
		ret+=tra[x];
		x-=(x&-x);
	}
	return ret;
}
void solve(int l,int r)
{
	if(l==r)return;
	int mid=(l+r)>>1,ql=l,qr=mid+1;
	for(int i=l;i<=r;i++){
		if(q[i].t<=mid){
			tmp[ql++]=q[i];
			if(q[i].v)update(q[i].y,q[i].v);
		}
		else{
			tmp[qr++]=q[i];
			if(!q[i].v)ans[q[i].id]+=query(q[i].y);
		}
	}
	for(int i=l;i<=r;i++)
		if(q[i].t<=mid&&q[i].v)update(q[i].y,-q[i].v);
	for(int i=l;i<=r;i++)q[i]=tmp[i];
	solve(l,mid);solve(mid+1,r);
}
int main()
{
	freopen("segment.in","r",stdin);
	freopen("segment.out","w",stdout);
	int i,x,l,r;
	n=gi();Q=gi();scanf("%s",ss+1);
	S.insert(0);S.insert(n+1);
	for(i=1;i<=n;i++){
		vis[i]=ss[i]-'0';
		if(!vis[i])S.insert(i);
	}
	for(i=1;i<=Q;i++){
		scanf("%s",op);
		if(op[0]=='t'){
			x=gi();it1=it2=S.lower_bound(x);
			if(vis[x]){
				it1--;
				cnt++,q[cnt]=node(*it1+1,*it2-1,i-las[*it1],cnt,0);
				if(*it1!=x-1)las[*it1]=i;
				if(*it2!=x+1)las[x]=i;
				S.insert(x);
			}
			else{
				it1--;it2++;
				if(*it1!=x-1)cnt++,q[cnt]=node(*it1+1,x-1,i-las[*it1],cnt,0);
				if(*it2!=x+1)cnt++,q[cnt]=node(x+1,*it2-1,i-las[x],cnt,0);
				S.erase(x);las[*it1]=i;
			}
			vis[x]^=1;
		}
		else{
			l=gi();r=gi()-1;
			cnt++,q[cnt]=node(l,r,0,cnt,++acnt);
			it1=S.lower_bound(l);
			if(*it1>r)ans[acnt]=i-las[*--it1];
		}
	}
	sort(q+1,q+cnt+1);
	solve(1,cnt);
	for(i=1;i<=acnt;i++)
		printf("%lld\n",ans[i]);
}

 

 

 

 

 

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