2019.08.15【NOIP提高組】模擬 B 組 排序、計算幾何+數論、高精度優化+二分圖/網絡流

0【NOIP2013模擬聯考3】庫特的向量(code)

從前在一個美好的校園裏,有一隻(棵)可愛的彎枝理樹。她內斂而羞澀,一副弱氣的樣子讓人一看就想好好疼愛她。僅僅在她身邊,就有許多女孩子想和她BH,比如鈴,庫特,等等。不過,除卻巫山不是雲,理樹的心理只有那個帥氣高大的男孩子——恭介,這讓女孩子們不得不終日唉聲嘆氣,以淚洗面。不過恭介是那樣強大而完美,根本沒有辦法擊敗他,她們也只好咬牙忍痛度日,以待反擊之時。

終於,她們獲得了一次機會。機智的庫特利用彈道學、密碼學、宇宙學的知識設計出了一個密室,可以讓進入的人無法從內部打開出口。庫特設計密碼的過程很奇葩,是由兩個用整數座標表示的n 維向量導出的。神奇的是,對於這兩個向量中的任意一個,無論如何將它的座標打亂(例如(a1,a2,a3)變成(a3,a1,a2)),打亂後的數量積都不會比原來的兩個向量的數量積小。而庫特就把原來的兩個向量的數量積作爲了密碼。現在她們只用把恭介引入就可以了。但是,好事多磨,由於她們的粗心大意,在測試密室的時候不小心把自己給關了進去,而且還帶走了密碼紙。在外面的鈴只找到了庫特寫着兩個打亂後的向量的草稿。哇呼~能不能解救這些萌妹子,就看你了。

對於50%的數據 n<=8 , |ai|,|bi|<=1000

對於100%的數據 n<=1000, |ai|,|bi|<=100000


向量a:(a1,a2,a3,...,an)(a_1,a_2,a_3,...,a_n),向量b:(b1,b2,b3,...,bn)(b_1,b_2,b_3,...,b_n)
兩個n維向量的數量積:(a1b1+a2b2+a3ba3+...+anbn)(a_1b_1+a_2b_2+a_3b_a3+...+a_nb_n)

然後這題求最小的向量積,那就把兩個向量中最小的座標和最大的座標乘
aia_ibib_i分別排序,一個升序另一個降序,然後按順序乘

那麼除了要開long long 就沒有任何要注意的地方了

#include <cstdio>
#include <algorithm> 

using namespace std;

int n;
long long ans;
int a[1005],b[1005];

bool comp(int a,int b){
	return a>b;
}

int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	sort(a+1,a+1+n);
	for (int i=1;i<=n;i++)
		scanf("%d",&b[i]);
	sort(b+1,b+1+n,comp);
	for (int i=1;i<=n;i++)
		ans=(long long)a[i]*b[i]+ans;
	printf("%lld",ans);
}

1 【NOIP2013模擬聯考3】恭介的法則(rule)

終於,在衆親們的奮鬥下,最終boss 恭介被關進了庫特設計的密室。正當她們鬆了一口氣時,這個世界卻發生了天翻覆地的變化:地面開始下沉,天空開始變成血紅色,海水沸騰……一幅世界末日的圖景。美魚從她手中的古籍《若山牧水詩歌集》中發現了原因:白鳥は かなしからずや 空の青 海のあをにも 染まずただよふ 。大(xia)意(shuo)就是狡猾的恭介在創造這個世界的時候就篡改了法則。而這個法則的起源,就是一隻生死之間的貓。這個貓被關在一個黑盒子裏,盒子裏有兩個毒氣罐,如果有任意一個毒氣罐被打開那麼貓將會被殺死,法則也能得到糾正。然而外界能控制的僅僅是這兩個毒氣罐被打開的概率。假設第一個毒氣罐被打開的概率爲1/x,第二個毒氣罐爲1/y(x,y 爲正整數),那麼當兩個概率和爲1/(n!)時,貓將會被莫名其妙地殺死。現在美魚想知道,有多少對(x,y)可以讓貓被莫名其妙殺死。

對於30%的數據 n<=6

對於60%的數據 n<=50

對於100%的數據 n<=700000


對題目大意總結,得要求有多少對(x,y)(x,y)滿足1/x+1/y=1/(n!)1/x+1/y=1/(n!)
對式子進行通分,得(x+y)/xy=1/(n!)(x+y)/xy=1/(n!)
然後分數運算,得(x+y)n!=xy(x+y)n!=xy
把括號拆開,得xn!+yn!=xyxn!+yn!=xy
把y放到同一邊,得xn!=xyn!yxn!=xy-n!y
把y提出來,得xn!=y(xn!)xn!=y(x-n!)
把(x-n!)除到左邊,得xn!/(xn!)=yxn!/(x-n!)=y

由x,y是正整數得xn!&gt;=(xn!)&gt;=1xn!&gt;=(x-n!)&gt;=1,則必有x&gt;n!x&gt;n!
這時設x=n!+kx=n!+kkk爲任意整數,則原始等於(n!+k)n!/(n!+kn!)=y(n!+k)n!/(n!+k-n!)=y
然後(n!2+kn!)/k=y(n!^2+kn!)/k=y
把括號拆開,得n!2/k+n!=yn!^2/k+n!=y
由y是正整數得kn!2k|n!^2
題目順利轉化爲n!2n!^2有多少個不同約數

n!2=(p1a1p2a2...pkak)2n!^2=(p_1^{a_1}*p_2^{a_2}*...*p_k^{a_k})^2,其中qiq_i爲質因子,aia_i爲每個質因子的指數
那麼就有n!2n!^2的約數個數爲(a12+1)(a22+1)...(ak2+1)(a_1*2+1)*(a_2*2+1)*...*(a_k*2+1)
可以理解爲對於一個質因子pip_i,可以選0個,選2個,…,選ai2a_i*2

哇這就變成了篩素數,算約數個數,並高精度

首先篩素數上一個歐拉篩

然後算約數個數
1——n有約數i的數的個數爲n/i
n一直除pi,每次除都加進ai

最後高精度(然而聽說可以FFT?)
壓位,
並有一個小優化即當乘進答案的數足夠大時才進行運算,可以減少運算的次數,詳見註釋
(加了上面那個優化就可以不吸氧啦)
並補零的輸出scanf("%09lld",ans)那個09表示補足9位,不足的位用0補齊

#pragma GCC optimize(3)
#pragma GCC optimize(2)    //額我不吸氧也可以過的[堅強.jpg]
#include <cstdio>

using namespace std;

const long long mod=1000000000;
int n,m,ans,tem=1;
int p[250000],b[700005];
long long e[250000];
long long a[100000];

void plus(long long x){
	for (int i=1;i<=a[0];i++)
		a[i]*=x;
	for (int i=1;i<=a[0];i++){
		long long g=a[i]/mod;
		a[i]%=mod;
		a[i+1]+=g;
		if (i==a[0]&&g!=0) a[0]++;
	}
}

int main(){
	scanf("%d",&n);
	for (int i=2;i<=n;i++){
		if (b[i]==0) p[++p[0]]=i;
		for (int j=1;p[j]*i<=n&&j<=p[0];j++){
			b[p[j]*i]=1;
			if (i%p[j]==0) break;
		}
	}
	a[1]=1;a[0]=1;
	for (int i=1;i<=p[0];i++){  //算每個質因數在1-n出現的次數
		for (int j=n;j>=p[i];) 
			j/=p[i],e[i]+=j;
	}
	for (int i=1;i<=p[0];i++){     //這裏乘法有一個小優化
		if (tem*(e[i]*2+1)>mod){//當要成進去的數快達到極限(很大)再乘進去,減少乘的次數
			plus(tem);
			tem=1;  	//乘完後臨時計數器清1
		}
		tem*=(e[i]*2+1);      //每次都往臨時計數器上堆數
	}
	if (tem>1) plus(tem);        //臨時計數器裏可能還有數沒有乘
	printf("%lld",a[a[0]]);
	for (int i=a[0]-1;i>=1;i--){		
		printf("%09lld",a[i]);  //這樣輸出可以補零呢
	}
}

2 【NOIP2013模擬聯考3】沙耶的玩偶(doll)

在美魚和理樹後援團拯救世界的同時,外表柔弱的理樹也開始堅強起來,思考着離開這個世界的辦法。誤打誤撞地,她遇上了正在教室破壞課桌打開迷宮入口的沙耶。沙耶告訴理樹,這個世界的出口就是這個迷宮的出口。於是理樹毫不猶豫地跟沙耶一起跳進了迷宮。在迷宮裏,兩個女孩子互幫互助,一會兒割繩子,一會兒泡溫泉,一會兒雕冰塊,跌跌撞撞地走到了終點。不出所料,終點也有一個機關在等着她們。

終點的機關是一個立着的mn 的方格棋盤,在有些格子上放了一個玩偶,而有些地方直接挖了個大坑。只有取走所有玩偶才能打開出口。但是,由於奇怪的設定,理樹和沙耶不能直接觸碰玩偶,他們需要操縱機器人來收集它。機器人的走法很奇怪,和國際象棋的馬有點像,只不過馬可以走任意方向的12 路線,它們只會由上往下走rc(或cr)的路線,不能回頭。而機器人一旦經過一個有玩偶的格子,那個格子上的玩偶將被回收,並且在機器人離開時,那個格子會變成一個坑。理樹可以把機器人放在任何一個有玩偶的格子上作爲起點,也可以在任何一個有玩偶的格子回收機器人。機器人行走可以視爲瞬移,只不過每一次設置新起點都會消耗1 時間。並且,有坑的格子不能落腳。

就在這個緊要關頭,玩偶狂熱愛好者的沙耶卻流着口水智商歸0。理樹不得不轉而求助你,幫忙計算出最少多少時間就能收集到所有玩偶。

30%的數據中,1<=M,N<=4,1<=R,C<=3。

70%的數據中,1<=M<=20,1<=N<=4,1<=R,C<=3。

100%的數據中,1<=M,N<=50,1<=R,C<=10。


由於這是一個有許多格子的圖,並每個格子與其他某些格子有某種關係
那麼可以看看二分圖/網絡流

難度當然主要在建圖

二分圖的建圖呢,就將二維的圖上的點標號,化爲一個個的點,將點複製一倍
設由(x1,y1)(x1,y1)可以跳到(x2,y2)(x2,y2),就將x1m+y1x1*m+y1x2m+y2+nmx2*m+y2+n*m連邊
答案是總玩偶數-最大匹配數,因爲每一個匹配都是由一個點跳向另外一個點,後面那個點顯然不用花費時間設置新起點,而剩下的點當然需要設置新起點

#include <cstdio>
#include <cstring>

using namespace std;

int dx[6],dy[6];
int m,n,e,c,ans,spa;
int b[55][55],co[5012],l[5012];
int ls[5012],ne[100005],y[100005];

bool match(int x){
	for (int i=ls[x];i;i=ne[i])
	if (co[y[i]]==0){
		int q=l[y[i]];
		l[y[i]]=x;
		co[y[i]]=1;
		if (q==0||match(q)) return 1;
		l[y[i]]=q;
	}
	return 0;
}

int main(){
	scanf("%d%d%d%d",&n,&m,&e,&c);
	if (e==c){
		dx[0]=2,dx[1]=e,dx[2]=e;
		dy[0]=2,dy[1]=c,dy[2]=-c;
	} else {
		dx[0]=4,dx[1]=e,dx[2]=e,dx[3]=c,dx[4]=c;
		dy[0]=4,dy[1]=c,dy[2]=-c,dy[3]=e,dy[4]=-e;
	}
	for (int i=0;i<n;i++){
		char ch[55];
		scanf("%s",ch+1);
		for (int j=1;j<=m;j++)
		if (ch[j]=='.') {
			b[i][j]=1;
			spa++;
			for (int k=1;k<=dx[0];k++){
				int x=i-dx[k],yy=j-dy[k];
				if (x>=0&&yy>0&&x<n&&yy<=m&&b[x][yy]==1)
					ne[++ne[0]]=ls[x*m+yy],ls[x*m+yy]=ne[0],y[ne[0]]=i*m+j+n*m;
			}
		}
	}
	for (int i=0;i<n;i++)
		for (int j=1;j<=m;j++)
		if (b[i][j]==1){
			memset(co,0,sizeof co);
			match(i*m+j);
		}
	for (int i=0;i<n;i++)
		for (int j=1;j<=m;j++)
		if (l[i*m+j+n*m]!=0&&b[i][j]==1) ans++;
	printf("%d",spa-ans);
}

開門那一瞬,陽光照在你的身上

文藝的後續:
——你的身形模糊又美麗,髮絲都泛着金光,背後是藍天白雲,青葉遠山
——那一瞬我以爲你是我的誰

競賽室真實的後續:
——我以爲你是AJ (by hjw)
——嚇得我關掉了瀏覽器

在教室更真實的後續:
——亮瞎了我的眼
——曬死了
——下次進教室麻煩不要走前門謝謝

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