2019.08.23【NOIP提高組】模擬 B 組 DP+快速冪、數論+最短路、DP+二分、二維樹狀數組

0 淘汰賽制

淘汰賽制是一種極其殘酷的比賽制度。2n名選手分別標號1,2,3,……2n-1,2^n,他們將要參加n輪的激烈角逐。每一輪中,將所有參加該輪的選手按標號從小到大排序後,第1位與第2位比賽,第3位與第4位比賽,第5位與第6位比賽……只有每場比賽的勝者纔有機會參加下一輪的比賽(不會有平局)。這樣,每輪將淘汰一半的選手。n輪過後,只剩下一名選手,該選手即爲最終的冠軍。

現在已知每位選手分別與其他選手比賽獲勝的概率,請你預測一下誰奪冠的概率最大。
  
  30%的數據滿足n<=3

100%的數據滿足n<=10


DP快樂

用f[i][j]表示第i輪比賽,j位選手獲勝的概率
轉移有
f[i][j]=f[i1][j](f[i1][k]a[j][k])f[i][j]=f[i-1][j]*(f[i-1][k]*a[j][k])

觀察一個選手在某一輪中可能對戰的選手,確定k的值

#include <cstdio>

using namespace std;

int n,m,s,d=1;
double f[15][1050],a[1050][1050],ans;

int cd(int x){
	return (x-1)/d+1;
}

int main(){
	scanf("%d",&n);
	m=1;
	for (int i=1;i<=n;i++) m*=2;
	for (int i=1;i<=m;i++){
		f[0][i]=1;
		for (int j=1;j<=m;j++){
			int d;
			scanf("%d",&d);
			a[i][j]=d;
			double c=100;
			a[i][j]=a[i][j]/c;
		}
	}
	for (int i=1;i<=n;i++){
		for (int j=1;j<=m;j++){
			f[i][j]=f[i-1][j];
			double l=0;
			int t=cd(j);
			if (t&1) t+=1;else t-=1;
			for (int k=1;k<=m;k++)
				if (cd(k)==t)
					l+=f[i-1][k]*a[j][k];
			f[i][j]*=l;
		}
		d*=2;
	}
	for (int i=1;i<=m;i++)
	if (f[n][i]>ans){
		ans=f[n][i];s=i;
	}
	printf("%d",s);
}

1 方程的解

佳佳碰到了一個難題,請你來幫忙解決。   對於不定方程a1+a2+……+ak-1+ak=g(x),其中k>=2且k∈N*,x是正整數,g(x)=x^x mod 1000(即xx除以1000的餘數),x,k是給定的數。我們要求的是這個不定方程的正整數解組數。   舉例來說,當k=3,x=2時,分別爲(a1,a2,a3)=(2,1,1),(1,2,1),(1,1,2).

對於40%的數據,ans<=10^16; 對於100%的數據,k<=100,x<=2^31-1,k<=g(x)。


g(x)好求,隨便快速冪

但是我當時就是沒想到怎麼求方案[我明白了我就是很菜我這就去辦退學手續.jpg]


可發現這個方案數相當於求C(g(x)-1,k-1),隨便用組合數學想想(隔板法?反正我想這個想明白)

然後組合數呢可以約分化簡,分解質因數,加加減減次方,再把次方高精度乘起來

#include <cstdio>

using namespace std;

const int N=1000;
int k,x,l[1000];
int a[1000],p[1000],bz[1000];

void ksm(){
	int y=x%1000,b=x;
	x=1;
	while (b){
		if (b&1) x=(x*y)%1000;
		y=(y*y)%1000;
		b>>=1;
	}
}

void pi(){
	for (int i=2;i<=1000;i++){
		if (bz[i]==0){
			p[++p[0]]=i;
		}
		for (int j=1;j<=p[0]&&p[j]*i<=1000;j++){
			bz[p[j]*i]=1;
			if (i%p[j]==0) break;
		}
	}
}

void pri(int x,int b){
	for (int i=1;i<=p[0];i++)
	if (x<=1)break;else{
		int k=0;
		while (x%p[i]==0&&x>0){
			x/=p[i];
			k++;
		}
		l[i]+=k*b;
	}
}

void cd(int x){
	int g=0;
	for (int i=1;i<=a[0];i++){
		a[i]=a[i]*x+g;
		g=a[i]/N;
		a[i]%=N;
		if (i==a[0]&&g>0) ++a[0];
	}
}

void plus(){
	a[1]=1,a[0]=1;
	int k=1;
	for (int i=1;i<=p[0];i++)
	if (l[i]){
		while (l[i]){
			k*=p[i];
			if (k>=N) cd(k),k=1;
			--l[i];
		}
	}
	cd(k);
}

void print(){
	printf("%d",a[a[0]]);
	for (int i=a[0]-1;i>=1;i--)
	printf("%03d",a[i]);
}

int main(){
	scanf("%d%d",&k,&x); 
	ksm();
	pi();
	for (int i=2;i<=k-1;i++) pri(i,-1);
	for (int i=x-k+1;i<=x-1;i++) pri(i,1);
	plus();
	print();
}

2 物流運輸

物流公司要把一批貨物從碼頭A運到碼頭B。由於貨物量比較大,需要n天才能運完。貨物運輸過程中一般要轉停好幾個碼頭。物流公司通常會設計一條固定的運輸路線,以便對整個運輸過程實施嚴格的管理和跟蹤。由於各種因素的存在,有的時候某個碼頭會無法裝卸貨物。這時候就必須修改運輸路線,讓貨物能夠按時到達目的地。但是修改路線是一件十分麻煩的事情,會帶來額外的成本。因此物流公司希望能夠訂一個n天的運輸計劃,使得總成本儘可能地小。

n( 1 <= n <= 100 )、m( 1 <= m<= 20 )


就是個DP呢

f[i]f[i]表示第i天的最小成本
f[i]=min(f[j]+k+(ij+1)a[1][m])f[i]=min(f[j]+k+(i-j+1)*a[1][m])其中a[1][m]是去掉i到j天不能走的碼頭後的最短路

最短路當然可以每次求啦,20的小數據用什麼最短路都可以呢

#include <cstdio>
#include <cstring>

using namespace std;

int n,m,k;
int a[25][25],g[25][25],p[25][105];
int f[105],b[25];

void read(){
	int e,d;
	scanf("%d%d%d%d",&n,&m,&k,&e);
	memset(a,0x3f,sizeof a);
	for (int i=1;i<=e;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		a[x][y]=a[y][x]=(z<a[x][y]?z:a[x][y]);
	}
	scanf("%d",&d);
	for (int i=1;i<=d;i++){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		for (int j=y;j<=z;j++)
			p[x][j]=1;
	}
}

void floyed(){
	for (int k=1;k<=m;k++){
		if (b[k]==0)
			for (int i=1;i<=m;i++)
			if (i!=k&&b[i]==0)
				for (int j=1;j<=m;j++)
				if (b[j]==0&&k!=j&&i!=j&&a[i][k]!=a[0][0]
			 		&&a[k][j]!=a[0][0]&&a[i][k]+a[k][j]<a[i][j])
					a[i][j]=a[i][k]+a[k][j];
		if (b[k]==1)
			for (int i=1;i<=m;i++)
				a[i][k]=a[k][i]=a[0][0];
	}
}

void dp(){
	memset(f,0x3f,sizeof f);
	f[0]=-k;
	for (int i=1;i<=n;i++){		
		memset(b,0,sizeof b);
		memcpy(g,a,sizeof a);
		for (int j=i;j>=1;j--){
			for (int l=1;l<=m;l++)
			if (p[l][j]==1) b[l]=1;
			memcpy(a,g,sizeof a);
			floyed();
			if (a[1][m]==a[0][0]) break;
			f[i]=(f[i]>f[j-1]+k+(i-j+1)*a[1][m]?f[j-1]+k+(i-j+1)*a[1][m]:f[i]);
		}
		memcpy(a,g,sizeof a);
	}
}

int main(){
	read();
	dp();
	printf("%d",f[n]);
}

3 矩陣乘法(mat)

給你一個 N*N 的矩陣,不用算矩陣乘法,但是每次詢問一個子矩形的第 K 小數。

矩陣中數字是 10 ^ 9 以內的非負整數;

20% 的數據: N<=100,Q<=1000 ;

40% 的數據: N<=300,Q<=10000 ;

60% 的數據: N<=400,Q<=30000 ;

100% 的數據: N<=500,Q<=60000 。


整體二分,二維樹狀數組

我和我的400寶貝兒

聽說復旦交大清北什麼的裸分的話三總必須400+呢。。。

看着我可憐的分數流下了悔恨的淚水。。。

假如我好好努力是不是可以和我家400寶貝兒重逢呢
從這學期開始再也別欠數學作業,從新學期開始像我同桌一樣好好寫英語筆記,從現在開始好好看語文老師佈置的書


我愛我吒我丙我李靖夫婦我申公公我太乙真人我龍王^ _ ^國漫衝鴨

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