1. 程式人生 > 其它 >UESTC - 第12屆 ACM 趣味賽一

UESTC - 第12屆 ACM 趣味賽一

A

B

先假設沒有 ”知道這 \(n\) 個人中普通市民的人數一定不少於組織中的人“ 這個條件,我們考慮為什麼沒有辦法將任何人的身份識別出來。不妨這樣想:每一個人只有兩種情況,要麼說謊話,要麼說真話,而所有說謊話的人和所有說真話的人給出的答案都會是一樣的。也就是說,我們只可能得到兩種答案,要麼是真實的情況,要麼是真實的情況取反(即,說謊話會被認為是說真話,說真話會被認為是說假話)。很顯然對於這兩種答案我們沒法判斷出那個是正確的,但是我們可以獲得一個資訊,也就是這群人已經被分為兩群,要麼其中一群是誠實的,另一群是不誠實的;要麼其中一群是不誠實的,另一群是誠實的。現在加上前面提到的那個條件,我們發現當這兩群人人數不等的時候,人數多的一定是普通市民;只有當人數相等的時候,無法將這兩群人歸類,此時總人數為偶數。答案顯然。

C

方法一

\(f[i][j]\) 表示前 \(i\) 關 Kaiser 玩 \(j\) 局而 Fatdog_Jo 玩 \(i-j\) 局的最少時間,則轉移方程為 \(f[i][j]=max\{f[i-1][j]+b[i],f[i-1][j-1]+a[i]\}\) ,該方法時間複雜度為 \(O(n^2)\)

方法二

先假設所有關都由 Fatdog_Jo 來玩,則 \(ans=\sum b[i]\)。設 \(c[i]=a[i]-b[i]\),則若第 \(i\) 關由 Kaiser 來玩,我們只需將 \(ans+=c[i]\)。現在有 \(n/2\) 關需要 Kaiser 來玩,我們只需要從 \(c[i]\)

中選出最小的 \(n/2\) 個加上去即可。該方法時間複雜度為 \(O(n\log n)\) 優於方法一。

D

暴力列舉旋風斬的回合數即可,顯然最多不超過 \(5000\) 次旋風斬所有隨從會死亡。時間複雜度為 \(O(na)\)

E

\(t\) 時刻成員 \(0\) 與成員 \(1\) 相遇,列出方程組:

1:\(y_0=ax_0+b\)

2:\(y_1=ax_1+b\)

3:\(x_0+v_{x_0}t=x_1+v_{x_1}t\)

4:\(y_0+v_{y_0}t=y_1+v_{y_1}t\)

由 3 得 \(x_0-x_1=-t(v_{x_0}-v_{x_1})\)

由 4 得 \(y_0-y_1=-t(v_{y_0}-v_{y_1})\)

兩式相除,整理得 \(v_{y_0}-v_{y_1}=a(v_{x_0}-v_{x_1})\)

移項得 \(v_{y_0}-av_{x_0}=v_{y_1}-av_{x_1}\)

即當上式成立(兩直線平行除外)時兩個成員相遇。特判一下平行的情況以及 \(a=0\) 的情況即可(\(Upd\)\(a=0\)不用特判)。

Code

#include <cstdio>
#include <map>
#include <utility>
using namespace std;

int n, a, b, x, y;
long long ans;
map<int, int> mp;
map<pair<int, int>, int> mppar;

int main(){
	scanf("%d%d%d", &n, &a, &b);
	if(!a){
		for(int i = 0; i < n; i++){
			scanf("%d%d%d", &x, &x, &y);
			ans += mp[y] - mppar[make_pair(x, y)];
			mp[y]++, mppar[make_pair(x, y)]++;
		}
	}else for(int i = 0; i < n; i++){
		scanf("%d%d%d", &x, &x, &y);
		ans -= mppar[make_pair(x, y)];
		mppar[make_pair(x, y)]++;
		x = y - a * x;
		ans += mp[x];
		mp[x]++;
	}
	printf("%lld", ans << 1);
	return 0;
}