1. 程式人生 > 實用技巧 >牛客IOI周賽21-提高組

牛客IOI周賽21-提高組

比賽連結:https://ac.nowcoder.com/acm/contest/9798#question

題號 標題 已通過程式碼 通過率 我的狀態
A 序列問題 點選檢視 34/406 通過
B 俄羅斯方塊 點選檢視 19/406 通過
C 旅行沒有商問題 點選檢視 20/96 未通過

A

推式子題,主要是細節特別多。討論 \(q\) 的範圍,分 5 類。

只需 \(B_{min}-A_{max} \geq q\)

\(i=A_{max},j=B_{min}\) , 考慮列舉 \(i,j\),則 \(A,B\) 集合中的其他數分別在 \([1,i-1],[j+1,n]\) 中任取。

易得:

\[ans=\sum _{i=1}^{n} 2^{i-1} \times \sum_{j=max\{i+q,1\}}^{n} 2^{n-j} \]

由於此式不能優美地化簡,對 \(q\) 分類。

  • $q \geq n $ 時, \(ans=0\).

  • \(q \in [0,n-1]\) 時,

    \[ans=\sum _{i=1}^{n-q} 2^{i-1} \times \sum_{j=i+q}^{n} 2^{n-j} \]

    \[= \sum _{i=1}^{n-q} 2^{i-1} \times (2^{n-i-q+1}-1) \]

    \[= (n-q-1) \times 2^{n-q} +1 \]

  • \(q\in [-n+1,-1]\) 時,有兩類,別漏了第二類。

    \[ans=\sum _{i=|q|+1}^{n} 2^{i-1} \times \sum_{j=i+q}^{n} 2^{n-j}+\sum _{i=1}^{|q|} 2^{i-1} \times \sum_{j=1}^{n} 2^{n-j} \]

    \[= \sum _{i=|q|+1}^{n-q} 2^{i-1} \times (2^{n-i-q+1}-1)+(2^{|q|}-1)\times (2^n-1) \]

    \[=(n-|q|)\times 2^{n+|q|}-2^n+2^{|q|}+(2^{|q|}-1)\times (2^n-1) \]

  • \(q \leq -n\) 時,隨便選 \(ans=(2^n-1)^2\)

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

const LL MOD=998244353;

LL fpow(LL x,LL k,LL MOD)
{
	LL res=1; x%=MOD;
	while(k) {
		if(k&1) res=res*x%MOD;
		x=x*x%MOD; k>>=1;
	}
	return res;
}

int T;
LL n,q;

int main()
{
//	freopen("1.in","r",stdin);

	scanf("%d",&T);
	while(T--) {
		scanf("%lld%lld",&n,&q);
		if(q>=n) printf("0\n"); 
		else if(q>=0) printf("%lld\n",((n-q-1)%MOD*fpow(2,n-q,MOD)%MOD+1+MOD)%MOD);
		else if(n+q<=0) printf("%lld\n",(fpow(2,n,MOD)-1)*(fpow(2,n,MOD)-1)%MOD);
		else if(q<0) printf("%lld\n",
			(((n+q)%MOD*fpow(2,n-q,MOD)%MOD-fpow(2,n,MOD)+fpow(2,-q,MOD))%MOD+
				(fpow(2,-q,MOD)-1)*(fpow(2,n,MOD)-1)%MOD+MOD)%MOD);
	}
	return 0;
}

B

B 是 大模擬,類似於 瑪雅游戲。

type=1 有 2 類,type=2 有 1 類,type=3 有4類。

我不太想寫,於是寫一類交一次。

最後,我只考慮了 6 類就 A 了。

資料太水

#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

const int N=11,INF=0x3f3f3f3f;

struct State
{
	int a[N][N];
	int tot;
	State() { memset(a,0,sizeof a); tot=0; }
	int get_height(int x)
	{
		for(int j=7;j>=1;j--) 
			if(a[j][x]) return j;
		return 0;
	}
	void suit()
	{
		int i,j,flag,k;
		for(i=7;i>=1;i--) {
			flag=0;
			for(j=1;j<=6;j++) 
				if(a[i][j]) flag++;
			
			if(flag==6) {
				for(k=i;k<=7;k++) {
					for(j=1;j<=6;j++) {
						a[k][j]=a[k+1][j];
					}
				}
				tot++;
				suit();
				return;
			}
		}
	}
	
	void print() const
	{
		puts("===========================");
		int i,j;
		for(i=7;i>=1;i--,printf("\n")) 
			for(j=1;j<=6;j++)
				printf("%d ",a[i][j]);
		puts("===========================");
	}
};

int n;
int type[N];
int ans;

void dfs(int step,State s)
{
//	s.print();
	if(step==n+1) {
		ans=max(ans,s.tot);
		return;
	}
	
	int i,j,h;
	State v;
	
	if(type[step]==1) {
		// 橫著放。 
		for(i=0;i<3;i++) {
			v=s;
			h=0;
			for(j=1;j<=4;j++) 
				h=max(h,v.get_height(i+j));
			
			if(h+1<=7) {
				for(j=1;j<=4;j++) 
					v.a[h+1][i+j]=1;
				v.suit();
				dfs(step+1,v);
			}
		}
		// 豎著放。 
		for(i=1;i<=6;i++) {
			v=s;
			h=v.get_height(i);
			
			if(h+4<=7) {
				for(j=1;j<=4;j++) v.a[h+j][i]=1;
//				v.print();
				v.suit();
//				v.print();
				dfs(step+1,v);
			}
		}
	}
	
	else if(type[step]==2) {
		for(i=0;i<5;i++) {
			v=s;
			h=0;
			for(j=1;j<=2;j++) {
				h=max(h,v.get_height(i+j));
			}
			if(h+2<=7) {
//				v.print();
				for(j=1;j<=2;j++)
					v.a[h+1][i+j]=v.a[h+2][i+j]=1;
//				v.print();
				v.suit();
//				v.print();
				dfs(step+1,v);
			} 
		}
	}
	
	else if(type[step]==3) {
		// A.
		for(i=0;i<4;i++) {
			v=s,h=0;
			
			for(j=1;j<=3;j++)
				h=max(h,v.get_height(i+j));
			
			if(h+2<=7) {
				for(j=1;j<=3;j++)
					v.a[h+1][i+j]=1;
				v.a[h+2][i+3]=1;
				
				v.suit();
				dfs(step+1,v);
			}
		}
		// B.
		for(i=0;i<5;i++) {
			v=s,h=0;
			for(j=1;j<=2;j++) {
				h=max(h,v.get_height(i+j));
			}
			
			if(h+3<=7) {
				v.a[h+1][i+1]=1;
				v.a[h+2][i+1]=1;
				v.a[h+3][i+1]=1;
				v.a[h+1][i+2]=1;
				
				v.suit();
				dfs(step+1,v);
			}
		}
		
		// C.
		// ***
		// *
		for(i=0;i<4;i++) {
			v=s; h=0;
			h=max(h,v.get_height(i+1)+1);
			h=max(h,v.get_height(i+2));
			h=max(h,v.get_height(i+3));
			
			if(h+1<=7) {
				v.a[h][i+1]=1;
				v.a[h+1][i+1]=1;
				v.a[h+1][i+2]=1;
				v.a[h+1][i+3]=1;
				
				v.suit();
				dfs(step+1,v);
			}
		}
	}

}

int main()
{
//	freopen("1.in","r",stdin);
	
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++) 
		scanf("%d",&type[i]);
	
	State s;
	dfs(1,s);
	cout<<ans<<endl;
	return 0;
}

話說輸出 (n+1)/2 能獲得 70pts.

其實熟悉了此類dfs,寫起來也不難。

C

連結:https://ac.nowcoder.com/acm/contest/9798/C
來源:牛客網

給出n個點,m條邊的無向圖。滿足無重邊、自環,不保證連通。某人在圖上依次訪問d個節點(即所經過的所有節點構成的序列長度為d)。n個點中有k個點必須至少經過一次。起點、終點任選。求滿足條件的方案數對109+7取模的值

想了一個狀壓,然後用矩乘優化,80pts.

#include<queue>
#include<bits/stdc++.h>

using namespace std;
typedef long long LL;
typedef unsigned long long ULL;

const int N=20+1;
const LL MOD=1e9+7;

int n,m,day,city;

LL f[N][64],g[N][64];
// f[i][j][k] 表示 經過了 i 個城市,現在在 j , 經過想要城市的點集為 k 的方案數。 
int a[N];
int w[N][N];

void solve()
{
	int i,j,k,u,v;
	for(i=0;i<n;i++) {
		if(~a[i]) f[i][1<<a[i]]=1;
		else f[i][0]=1;
	}
	for(i=2;i<=day;i++) {
//		for(k=0;k<(1<<city);k++)
//			for(j=0;j<n;j++)
//				printf("f[%d][%d] = %lld\n",j,k,f[j][k]);
		memcpy(g,f,sizeof g);
		memset(f,0,sizeof f);
		for(k=0;k<(1<<city);k++) {
			for(j=0;j<n;j++) {
				if(~a[j] && !((k>>a[j])&1)) continue;
				
				
				if(~a[j]) {
					u=k-(1<<a[j]);
					for(v=0;v<n;v++) {
						if(~a[v] && !((u>>a[v])&1)) continue;
						if(!w[j][v]) continue;
					
						f[j][k]=(f[j][k]+g[v][u])%MOD;
					}
				} 
			
				u=k;		
				for(v=0;v<n;v++) {
					if(~a[v] && !((u>>a[v])&1)) continue;
					if(!w[j][v]) continue;
				
					f[j][k]=(f[j][k]+g[v][u])%MOD;
				}
			}
		}
		

	}
	
	LL ans=0;
	for(i=0;i<n;i++)
		ans=(ans+f[i][(1<<city)-1])%MOD;
	printf("%lld\n",ans%MOD);	
}

int get(int x,int y) { return x*(1<<city)+y+1; }

struct Matrix 
{
	LL a[2000][2000];
	int n,m;
	Matrix(int n=0,int m=0) : n(n),m(m) {
		memset(a,0,sizeof a);
	}
};

Matrix mul(const Matrix &x,const Matrix &y)
{
	Matrix z;
	z.n=x.n,z.m=y.m;
	int i,j,k;
	for(i=1;i<=z.n;i++) {
		for(j=1;j<=z.m;j++) {
			for(k=1;k<=y.n;k++) 
				z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%MOD)%MOD;
		}
	}
	return z;
}

Matrix fpow(Matrix x,LL k,Matrix res)
{
	while(k) {
		if(k&1) res=mul(x,res);
		x=mul(x,x); k>>=1;
	}
	return res;
}

void print(Matrix x)
{
	for(int i=1;i<=x.n;i++,printf("\n"))
		for(int j=1;j<=x.m;j++) 
			printf("%lld ",x.a[i][j]);
	printf("\n");
}

void Work()
{
	int i,j,k,u,v;
	const int S=(1<<city);
	const int Row=get(n-1,S);
	Matrix A(Row,1);
	Matrix C(Row,Row);
	
	for(i=0;i<n;i++) {
		if(~a[i]) A.a[get(i,1<<a[i])][1]=1;
		else A.a[get(i,0)][1]=1;
	}
//	print(A);
	for(k=0;k<(1<<city);k++) {
		for(j=0;j<n;j++) {
			if(~a[j] && !((k>>a[j])&1)) continue;
			
			if(~a[j]) {
				u=k-(1<<a[j]);
				for(v=0;v<n;v++) {
					if(~a[v] && !((u>>a[v])&1)) continue;
					if(!w[j][v]) continue;

					C.a[get(j,k)][get(v,u)]++;
				}
			} 
		
			u=k;		
			for(v=0;v<n;v++) {
				if(~a[v] && !((u>>a[v])&1)) continue;
				if(!w[j][v]) continue;
			
				C.a[get(j,k)][get(v,u)]++;
			}
//			print(C);
		}
	}
	A=fpow(C,day-1,A);
//	print(C);
//	print(A);
	LL ans=0;
	for(i=0;i<n;i++)
		ans=(ans+A.a[get(i,(1<<city)-1)][1])%MOD;
	printf("%lld\n",ans%MOD);	
}

int main()
{
//	freopen("1.in","r",stdin);
	int i;
	int x,y;
	
	cin>>n>>m>>day>>city;
	memset(a,-1,sizeof a);
	for(i=0;i<city;i++) {
		cin>>x;
		x--;
		a[x]=i;
	}
	for(i=1;i<=m;i++) {
		cin>>x>>y;
		x--,y--;
		w[x][y]=w[y][x]=1;
	}
	
//	if(day<=1000 || n<=5) solve();
	Work();
	return 0;
}

正解咕咕咕中。