1. 程式人生 > 其它 >4.13省選模擬

4.13省選模擬

這是部落格園的第一百篇隨筆\(!\)

不說別的,感覺程式碼能力真的提升很大,認真敲程式碼真的很暢快,好嘛\(!\)

\(T1\)

考場上一眼看出來正解,半平面交不會寫,就造了一個假的半平面交。。(複雜度不對)

考場暴力程式碼(有一些細節也沒處理好,考場上寫了\(240+\))

#include<bits/stdc++.h>
#define int long long
#define MAXN 200005
#define INF 1e30
using namespace std;
int sta[MAXN],son[MAXN],top1[MAXN],zx[MAXN][20],f[MAXN],top;
int head[MAXN],nxt[MAXN],to[MAXN],tot;
int n,m,cnt,siz[MAXN],dep[MAXN];
struct node
{
	   int a,s,id;
}poz[MAXN];
struct LINE
{
	   int k,st,ed,id,js,qs;
}Line[MAXN];
void add(int u,int v)
{ 
     tot++;
     to[tot]=v;
     nxt[tot]=head[u];
     head[u]=tot;
}
bool cmp(node x,node y)
{
	 if(x.a!=y.a) return x.a<y.a;
	 return x.id<y.id;
}
void dfs_pre(int now,int fa)
{
	 zx[now][0]=fa;
	 for(int i=1;i<=18;i++)
	 {
	 	 zx[now][i]=zx[zx[now][i-1]][i-1];
	 }
	 int maxn=-1;
	 dep[now]=dep[fa]+1;
	 siz[now]=1;
	 f[now]=fa;
	 for(int i=head[now];i;i=nxt[i])
	 {
	     int y=to[i];
		 if(y==fa) continue;	 
	     dfs_pre(y,now);
	     siz[now]+=siz[y];
	     if(siz[y]>maxn)
	     {
	     	maxn=siz[y];
	     	son[now]=y;
	     }
	 }
}
void dfs_top(int now,int topn)
{
	 top1[now]=topn;
     if(!son[now]) return ;
	 dfs_top(son[now],topn);
	 for(int i=head[now];i;i=nxt[i])
	 {
	 	 int y=to[i];
	 	 if(top1[y]) continue;
	 	 dfs_top(y,y);
	 }
}
int LCA(int x,int y)
{ 
    while(top1[x]!=top1[y])
    {
    	  if(dep[top1[x]]<dep[top1[y]]) swap(x,y);
    	  x=f[top1[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    return x;
}
int LEN(int x,int y)
{
	return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
int Find(int now,int dp)
{
	for(int i=18;i>=0;i--)
	{
		if((dp>>i)&1) now=zx[now][i];
	}
	return now;
}
//注意編號順序
signed main()
{
	freopen("ant.in","r",stdin);
	freopen("ckant.out","w",stdout);
    scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&poz[i].s);
		poz[i].id=i;
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%lld",&poz[i].a);
	}
//	for(int i=1;i<=n;i++)
//	{
//		poz[i].s+=poz[i].a;
//	}
	sort(poz+1,poz+1+n,cmp);
	int top=0;
	for(int i=1;i<=n;i++)
	{
		while(top&&poz[sta[top]].s<=poz[i].s) top--;
		sta[++top]=i;
	}
//	for(int i=1;i<=top;i++)
//	{
//		cout<<"id: "<<poz[sta[i]].id<<"\n";
//	}
	Line[cnt=1].id=poz[sta[1]].id;
	Line[cnt=1].st=0;
	int l=1;
//	cout<<top<<endl;
//	return 0;
    while(l<top)
    {
//    	  cout<<l<<"\n";
//          cout<<poz[sta[l]].a<<"\n";
    	  int jd=INF,xz;
          int s=poz[sta[l]].s;
          int a=poz[sta[l]].a;
     	  for(int i=l+1;i<=top;i++)
    	  {
    	  	  int s2=poz[sta[i]].s;
    	  	  int a2=poz[sta[i]].a;
    	  	  int x=ceil((s2-s)*1.0/(a-a2)*1.0);
    	  	  if(s+x*a==s2+x*a2)
    	  	  {
    	  	  	 if(poz[sta[l]].id>poz[sta[i]].id)
    	  	  	 {
    	  	  	 	 x++;
    	  	  	 }
    	  	  }
              if(x<jd)
              {
              	 jd=x;
              	 xz=i;
              }
              else if(x==jd&&poz[sta[i]].s+x*poz[sta[i]].a>=poz[sta[xz]].s+x*poz[sta[xz]].a) 
              {
              	   jd=x;
              	   xz=i;
              }
//              cout<<"jd: "<<jd<<"\n";
    	  }
          Line[cnt].ed=jd-1;
    	  ++cnt;
    	  Line[cnt].id=poz[sta[xz]].id;
    	  Line[cnt].st=jd;
    	  Line[cnt].k=poz[sta[xz]].a;
    	  l=xz;
//    	  cout<<"xz: "<<xz<<" "<<poz[sta[xz]].id<<"\n";
    }
    Line[cnt].ed=INF;

    for(int i=1,u,v;i<n;i++)
    {
    	scanf("%lld%lld",&u,&v); u++; v++;
    	add(u,v); add(v,u);
    }
    dfs_pre(1,1);
    dfs_top(1,1);
    int now=1;
    Line[0].js=1;
    for(int i=1;i<=cnt;i++)
    {
    	Line[i].qs=Line[i-1].js;
    	int id=Line[i].id;
		int Len=LEN(now,id);
    	int lca=LCA(now,id);
    	int MidLen=LEN(now,LCA(now,id));
    	int TimLen=Line[i].ed-Line[i].st+1;
    	if(TimLen<MidLen)
    	{
    	   	Line[i].js=Find(Line[i].qs,TimLen);
    	}
    	else if(TimLen==MidLen)
    	{
    		 Line[i].js=lca;
    	}
    	else if(TimLen>MidLen&&TimLen<Len)
    	{
    		 TimLen-=MidLen;
    		 Line[i].js=Find(id,LEN(id,lca)-TimLen);
    	}
    	else
    	{
    		 Line[i].js=id;
    	}
    	now=Line[i].js;
//    	cout<<"poi: "<<i<<" "<<Line[i].qs<<" "<<Line[i].js<<"\n";
    }
    for(int i=1,T;i<=m;i++)
    {
    	scanf("%lld",&T);
    	int l=1,r=cnt,mid,ans;
    	while(l<=r)
    	{
    		  mid=(l+r)>>1;
    		  if(Line[mid].ed>=T-1)
    		  {
    		  	 ans=mid;
    		  	 r=mid-1;
    		  }
    		  else
    		  {
    		  	 l=mid+1;
    		  }
    	}
//    	cout<<"mid: "<<ans<<"\n";
    	int Ans;
        int id=Line[ans].js;
        int now=Line[ans].qs;
        int Len=LEN(id,now);
		int lca=LCA(now,id);
        int TimLen=T-Line[ans].st;
        int MidLen=LEN(now,LCA(now,id));
        if(TimLen<MidLen)
    	{
    	   	Ans=Find(Line[ans].qs,TimLen);
    	}
    	else if(TimLen==MidLen)
    	{
    		 Ans=LCA(now,id);
    	}
    	else if(TimLen>MidLen&&TimLen<Len)
    	{
    		 TimLen-=MidLen;
    		 Ans=Find(id,LEN(id,lca)-TimLen);
    	}
    	else
    	{
    		 Ans=id;
    	}
    	printf("%lld\n",Ans-1);
//    	cout<<Ans-1<<"\n";
    }
}

考後重寫了一遍半平面交,改了改就過了

#include<bits/stdc++.h>
#define int long long
#define MAXN 200005
#define INF 1e30
using namespace std;
int sta[MAXN],son[MAXN],top1[MAXN],zx[MAXN][20],f[MAXN],top;
int head[MAXN],nxt[MAXN],to[MAXN],tot;
int n,m,siz[MAXN],dep[MAXN];
struct node
{
	   int k,b,id;
}poz[MAXN],T[MAXN];
struct line
{
	   int st,ed,id,js,qs;
}Line[MAXN];
bool cmp(node a,node b)
{
	 if(a.k!=b.k) return a.k<b.k;
	 if(a.b!=b.b) return a.b>b.b;
     return a.id>b.id;
}
int Get(node l1,node l2)
{
	int x=ceil((l2.b-l1.b)*1.0/(l1.k-l2.k)*1.0);
	if(l1.k*x+l1.b==l2.k*x+l2.b)
	{
	   if(l1.id>l2.id) x++;
	}
    return x;
}
void add(int u,int v)
{ 
     tot++;
     to[tot]=v;
     nxt[tot]=head[u];
     head[u]=tot;
}
void dfs_pre(int now,int fa)
{
	 zx[now][0]=fa;
	 for(int i=1;i<=18;i++)
	 {
	 	 zx[now][i]=zx[zx[now][i-1]][i-1];
	 }
	 int maxn=-1;
	 dep[now]=dep[fa]+1;
	 siz[now]=1;
	 f[now]=fa;
	 for(int i=head[now];i;i=nxt[i])
	 {
	     int y=to[i];
		 if(y==fa) continue;	 
	     dfs_pre(y,now);
	     siz[now]+=siz[y];
	     if(siz[y]>maxn)
	     {
	     	maxn=siz[y];
	     	son[now]=y;
	     }
	 }
}
void dfs_top(int now,int topn)
{
	 top1[now]=topn;
     if(!son[now]) return ;
	 dfs_top(son[now],topn);
	 for(int i=head[now];i;i=nxt[i])
	 {
	 	 int y=to[i];
	 	 if(top1[y]) continue;
	 	 dfs_top(y,y);
	 }
}
int LCA(int x,int y)
{ 
    while(top1[x]!=top1[y])
    {
    	  if(dep[top1[x]]<dep[top1[y]]) swap(x,y);
    	  x=f[top1[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    return x;
}
int LEN(int x,int y)
{
	return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
int Find(int now,int dp)
{
	for(int i=18;i>=0;i--)
	{
		if((dp>>i)&1) now=zx[now][i];
	}
	return now;
}
signed main()
{
	freopen("ant.in","r",stdin);
	freopen("ant.out","w",stdout);
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)
    {
    	scanf("%lld",&poz[i].b);
    	poz[i].id=i;
	}
    for(int i=1;i<=n;i++)
    {
    	scanf("%lld",&poz[i].k);
	}
    sort(poz+1,poz+1+n,cmp);
    T[top=1]=poz[1];
    for(int i=2;i<=n;i++)
    {
    	if(poz[i].k==poz[i-1].k) continue;
    	while(top>1&&(Get(T[top-1],poz[i])<Get(T[top-1],T[top])||(poz[i].k*Get(T[top-1],poz[i])+poz[i].b>T[top].k*Get(T[top-1],poz[i])+T[top].b&&Get(T[top-1],poz[i])==Get(T[top-1],T[top])))) top--; 
        T[++top]=poz[i];
	}
	Line[0].ed=-1;
    for(int i=1;i<=top;i++)
    {
        Line[i].id=T[i].id;
		Line[i].st=Line[i-1].ed+1;
		if(i!=top) Line[i].ed=Get(T[i],T[i+1])-1;
	}
    Line[top].ed=INF;
//    for(int i=1;i<=top;i++)
//    {
//    	cout<<Line[i].id<<" "<<Line[i].st<<" "<<Line[i].ed<<"\n";
//	}
//	return 0;
    for(int i=1,u,v;i<n;i++)
    {
    	scanf("%lld%lld",&u,&v); u++; v++;
    	add(u,v); add(v,u);
    }
    dfs_pre(1,1);
    dfs_top(1,1);
    int now=1;
    Line[0].js=1;
    for(int i=1;i<=top;i++)
    {
    	Line[i].qs=Line[i-1].js;
    	int id=Line[i].id;
		int Len=LEN(now,id);
    	int lca=LCA(now,id);
    	int MidLen=LEN(now,LCA(now,id));
    	int TimLen=Line[i].ed-Line[i].st+1;
    	if(TimLen<MidLen)
    	{
    	   	Line[i].js=Find(Line[i].qs,TimLen);
    	}
    	else if(TimLen==MidLen)
    	{
    		 Line[i].js=lca;
    	}
    	else if(TimLen>MidLen&&TimLen<Len)
    	{
    		 TimLen-=MidLen;
    		 Line[i].js=Find(id,LEN(id,lca)-TimLen);
    	}
    	else
    	{
    		 Line[i].js=id;
    	}
    	now=Line[i].js;
//    	cout<<"poi: "<<i<<" "<<Line[i].qs<<" "<<Line[i].js<<"\n";
    }
    for(int i=1,T;i<=m;i++)
    {
    	scanf("%lld",&T);
    	int l=1,r=top,mid,ans;
    	while(l<=r)
    	{
    		  mid=(l+r)>>1;
    		  if(Line[mid].ed>=T-1)
    		  {
    		  	 ans=mid;
    		  	 r=mid-1;
    		  }
    		  else
    		  {
    		  	 l=mid+1;
    		  }
    	}
//    	cout<<"mid: "<<ans<<"\n";
    	int Ans;
        int id=Line[ans].js;
        int now=Line[ans].qs;
        int Len=LEN(id,now);
		int lca=LCA(now,id);
        int TimLen=T-Line[ans].st;
        int MidLen=LEN(now,LCA(now,id));
        if(TimLen<MidLen)
    	{
    	   	Ans=Find(Line[ans].qs,TimLen);
    	}
    	else if(TimLen==MidLen)
    	{
    		 Ans=LCA(now,id);
    	}
    	else if(TimLen>MidLen&&TimLen<Len)
    	{
    		 TimLen-=MidLen;
    		 Ans=Find(id,LEN(id,lca)-TimLen);
    	}
    	else
    	{
    		 Ans=id;
    	}
    	printf("%lld\n",Ans-1);
    }
}

\(T2\)

大力插頭\(dp\)即可

源自題解.......

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
const int x5[10]={1,5,25,125,625,3125,15625,78125};
int v,past,now;
int f[2][480000],n,m,k,s[100][10],x,y,all;
int b[480000][9];
void out()
{
	for (int k=0;k<all;k++)	if (f[past][k])
	{
		for (int j=0;j<=m;j++)	printf("%d",b[k][j]);
		printf(":%d\n",f[past][k]);
	}
}
inline void add(int &a)	{a+=v,a%=mod;}
void init()
{
	all=6;
	for (int i=0;i<m;i++)	all*=5;
	for (int i=0;i<all;i++)
	{
		int temp=i;
		for (int j=0;j<m;j++)	b[i][j]=temp%5,temp/=5;
		b[i][m]=temp;
	}
}

int main()
{
	freopen("tetris.in","r",stdin);
	freopen("tetris.out","w",stdout);
	scanf("%d%d%d",&n,&m,&k);
	while (k--)
	{
		scanf("%d%d",&x,&y);
		s[x][y]=1;
	}
	init();
	
	now=0,past=1;
	f[now][0]=1;
	
	for (int i=0;i<n;i++)
		for (int j=0;j<m;j++)
		{
			swap(now,past);
			memset(f[now],0,sizeof f[now]);
			//printf("%d %d\n",i,j);
			//out();
			for (int k=0;k<all;k++)
			{
				v=f[past][k];
				if (!v)	continue;
				if (!j && b[k][m])	continue;
				if (s[i][j])
				{
					if (!b[k][m] && !b[k][j])	add(f[now][k]);
					continue;
				}
				int gao=1,temp=k-b[k][m]*x5[m]-b[k][j]*x5[j];
				if (b[k][m] && b[k][j])
				{
					if (b[k][m]==5)	continue;
					if (b[k][m]==4)	gao+=2;else gao+=4-b[k][m];
					if (b[k][j]==4)	gao+=2;else gao+=4-b[k][j];
					if (gao==4)	add(f[now][temp]);
					else if (gao<4)add(f[now][temp+x5[j]]),add(f[now][temp+x5[m]]);
				}
				else if (b[k][m])
				{
					if (b[k][m]==3)	
						add(f[now][temp+x5[j]+x5[m]]),
						add(f[now][temp+x5[j]*2]),
						add(f[now][temp+x5[m]*2]);
					if (b[k][m]==5 || b[k][m]==2)
						add(f[now][temp+x5[j]]),
						add(f[now][temp+x5[m]]);
					if (b[k][m]==4)
						add(f[now][temp+x5[m]]);
					if (b[k][m]==1)
						add(f[now][temp]);
						
				}
				else if (b[k][j])
				{
					if (b[k][j]==3)	
						add(f[now][temp+x5[j]+x5[m]]),
						add(f[now][temp+x5[j]*2]),
						add(f[now][temp+x5[m]*5]);
					if (b[k][j]==2)
						add(f[now][temp+x5[j]]),
						add(f[now][temp+x5[m]]);
					if (b[k][j]==4)
						add(f[now][temp+x5[j]]);
					if (b[k][j]==1)
						add(f[now][temp]);
				}
				else
				{
					add(f[now][temp+x5[j]*3]);
					add(f[now][temp+x5[j]*4+x5[m]]);
					add(f[now][temp+x5[j]+x5[m]*4]);
					add(f[now][temp+x5[m]*3]);
				}
			}
		}
	printf("%d\n",f[now][0]);
}

\(T3\)

計數題

如果把各種知識放在一起考慮,那麼很麻煩,我們可以考慮一個一個知識去算,然後最後進行一下容斥操作

\(f(k)\)表示前\(k\)道題會做,後\(n-k\)道題不一定的方案數

\(g(k)\)表示前\(k\)道題會做,後\(n-k\)道題不會做的方案數

比較顯然,\(f(k)\)包含\(g(k),\)我們需要把\(g(k)\)容斥出來

還是較為套路的二項式反演

\(f(k)=\sum C(j,k) g(j)\)

\(g(k)=\sum (-1)^{j-k} f(j)\)

我們考慮求\(f(x)\)可以把各種知識分開考慮,最後乘起來

我一直再想,這個會不會出現,前面符合要求,後面不符合要求的情況

其實我們每一步都是保證前\(n-k\)個,可以符合條件的方案,我一開始以為最後還要交換順序之類的

就想的過於麻煩了,然後最後大概就是列舉\(Q\)每一個知識點的實力,最後相乘就好了

至於為什麼二項式反演,我們強制讓後面都嚴格大於不可以嗎\(?\)

考慮最後他要會做這道題,那麼就是說,我們總的中位數要滿足條件

但是又說,我們這個即使前\(k\)個這個知識點會做,後面知識點的也不一定滿足,這就是我們二項式容斥的必要我們最後\(f(k)\)表示的是全部知識點的情況

考慮每一種知識的時候,我們可以列舉\(Q\)的水平,假設為\(x,\)我們有一個\(a\)的範圍使得既滿足前\(n-k\)可做,後面的可能不可做,但是這道題會做...(有點混亂)

我們讓\((n+1)/2<=a+k<=n\)

最後保留\(x,\)求出多項式係數,然後把多項式乘起來就好了

#include<bits/stdc++.h>
#define mod 1000000007
#define int long long 
#define maxn 102
using namespace std;
int C[105][105];
int sigma[105][105];
int n,m,k,u[105],p[105][105];
int ji;
int sqr(int x)	{return (x*x)%mod;}
int qming(int a,int b)
{
	if (!b)	return 1;
	if (b&1)	return (sqr(qming(a,b>>1))*a)%mod;
	return sqr(qming(a,b>>1));
}
void initC()
{
	C[0][0]=1;
	C[1][0]=C[1][1]=1;
	for (int i=2;i<=maxn;i++)
	{
		C[i][0]=C[i][i]=1;
		for (int j=1;j<i;j++)	C[i][j]=C[i-1][j-1]+C[i-1][j],C[i][j]%=mod;
	}
}

void initp()
{
	ji=1;
	for (int i=0;i<m;i++)	ji*=u[i],ji%=mod;
	int temp;
	for (int i=0;i<m;i++)
	{
		p[i][0]=1;
		for (int j=1;j<=maxn;j++)
		{
			temp=p[i][j-1];
			temp*=u[i];
			temp%=mod;
			p[i][j]=temp;
		}
	}
}

void initsigma()
{
	int temp;
	sigma[0][1]=1;
	for (int i=1;i<=maxn;i++)
	{
		sigma[i][i+1]=1;
		for (int j=0;j<i;j++)
			for (int k=1;k<=j+1;k++)
			{
				temp=C[i+1][j];
				temp*=sigma[j][k];
				temp%=mod;
				if (((i-j)&1)==0) temp=mod-temp;
				sigma[i][k]+=temp%mod;
				sigma[i][k]%=mod;
			}
		int chu=qming(i+1,mod-2);  
		for (int k=1;k<=i+1;k++)
		{
			temp=sigma[i][k];
			temp*=chu;
			sigma[i][k]=temp%mod;
		}
	}
}

int f[105];
int sigmaf[105];


int count(int x,int t)
{
	int ret=0,now=1,temp;
	for (int i=0;i<=t;i++)
	{
		ret+=now*sigmaf[i];
		ret%=mod;
		now*=x;
		now%=mod;
	}
	return ret;
}

void getsigmaf(int t)
{
	memset(sigmaf,0,sizeof sigmaf);
	int temp;
	for (int i=0;i<=t;i++)
	{
		for (int j=1;j<=i+1;j++)
		{
			temp=f[i];
			temp*=sigma[i][j];
			temp%=mod;
			sigmaf[j]+=temp;
			sigmaf[j]%=mod;
		}
	}
}

int solve(int k)
{
	int ret=1,temp;
	int a=n-k;
	int b=(n+1)/2;
	b-=k;
	b=max(b,0ll);
	for (int o=0;o<m;o++)
	{
		memset(f,0,sizeof f);
		for (int i=b;i<=a;i++)
		{
			for (int j=0;j<=a-i;j++)
			{
				temp=C[a-i][j];
				temp*=p[o][a-i-j];
				temp%=mod;
				if (j&1)	temp=mod-temp;
				temp*=C[a][i];
				temp%=mod;
				f[j+i+k]+=temp;
				f[j+i+k]%=mod;
			}
		}
		getsigmaf(n);
		ret*=count(u[o],n+1);
		ret%=mod;
	}
	//ret*=qming(ji,k);
	//ret%=mod;
	return ret;
}

signed main()
{
//	freopen("problem.in","r",stdin);
//	freopen("problem.out","w",stdout);
	initC();
	initsigma();
	int T;
	scanf("%lld",&T);
	while (T--)
	{
		scanf("%lld%lld%lld",&m,&n,&k);
		for (int i=0;i<m;i++)	scanf("%lld",u+i);
		initp();
		int ans=0,bj=1;
		int temp;
		for (int i=k;i<=n;i++)
		{
			temp=solve(i);
			temp*=C[n-k][i-k];
			ans+=bj*temp;
			ans%=mod;
			if (ans<0)	ans+=mod;
			bj*=-1;
		}
		printf("%lld\n",ans);
	}
}