kuangbin數學訓練一

Fibsieve`s Fantabulous Birthday

LightOJ - 1008

題意:主要看題目給出的那張圖片。一個N*M的格子裏面有規律的分佈着一些數,然後題目給出圖中的一個數,需要你求這個數的座標(橫爲x,豎爲y)
題面圖片

思路:數字的顏色已經說明了一切,顏色相同的就相當於一組,這個題目主要是數據大,不允許循環出現的,同一組數據開根號向上取整就剛好是當前的組數你說這不是巧了嗎這不是。可以定位到這個數字所在的組數那麼求出具體位置就很簡單了,先通過這個組數找到最中間的那個數座標就是 (組數,組數),具體值也好求,然後討論當前組數的奇偶,對座標做相應的加減就OK。

#include <bits/stdc++.h>
using namespace std;

int _;
long long n;

int main() {
	int cas = 0;
	scanf("%d", &_);
	while(_--) {
		scanf("%lld", &n);
		printf("Case %d: ", ++cas);
		long long cnt = ceil(sqrt(n));
		long long t = cnt*cnt-(cnt-1);
		long long ansx = cnt, ansy = cnt;
		if(t == n) printf("%lld %lld\n", ansx, ansy);
		else {
			long long change = abs(t-n);
			if(cnt%2) {
				if(t < n) ansx -= change;
				else ansy -= change;
			}
			else {
				if(t < n) ansy -= change;
				else ansx -= change;
			}
			printf("%lld %lld\n", ansx, ansy);
		}
	}
}

Knights in Chessboard

LightOJ - 1010

題意:求那個棋子在互不傷害的情況下能怎麼儘可能多的擺在同一個棋盤上。

題面圖片

思路:根據樣例,在草稿紙上畫一畫,看怎麼擺纔可以擺得最多,試了那個3 7的之後就不難發現它是在一行中,隔一個位置放一個棋子♟,下一行與上一行錯開,同一行照樣是隔一個棋子放一個。這樣min(n,m) > 2 的情況就完成了✅。只有一行的棋盤有幾個格子就放幾個這個很好理解,min(n,m) = 2 的就需要注意一下:

× × × ×
× × × ×

2*n 的棋盤應該這麼放才能達到最大。每4列一組討論一下就👌

#include <bits/stdc++.h>
using namespace std;

int _, n, m;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%d %d", &n, &m);
		printf("Case %d: ", ++cas);
		if(n < m) swap(n, m);
		if(m == 1) printf("%d\n", n);
		else if(m == 2) {
			int t = n%4;
			printf("%d\n", n/4*4+(t==0?0:(t>1?4:2)));
		}
		else {
			printf("%d\n", n*m%2?n*m/2+1:n*m/2);
		}	
	}
}

A Childhood Game

LightOJ - 1020

題意:A 和 B 兩個人在取彈珠,每個人每次可以取 1~2 顆,如果A先手,那麼最後取的人輸了;如果B先手,那麼最後取的人就贏了✌️。給出當前有幾顆彈珠和誰先手,要你求最後誰會贏。

思路:不同的人先手會有不同的遊戲規則,那麼就把這個當作兩個遊戲來分開找規律會比較清晰。

如果Alice先手,情況如下:

1 2 3 4 5 6 7
B A A B A A B

如果Bob先手,情況如下:

1 2 3 4 5 6 7
B B A B B A B

不難發現Alice先手就是 “BAA” 的規律, Bob先手就是“BBA”的規律。

#include <bits/stdc++.h>
using namespace std;

int _;
long long n;
string s;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lld", &n);
		cin >> s;
		printf("Case %d: ", ++cas);
		int t = n%3;
		if(s == "Alice") {
			if(t == 1) puts("Bob");
			else puts("Alice");
		}
		else {
			if(t == 0) puts("Alice");
			else puts("Bob");
		}
	}
}

Integer Divisibility

LightOJ - 1078

題意:給一個數 n, 再給一個數 m,問多少位的 m 可以被 n 整除,輸出最小符合條件的 “mmmmm…” 的位數。

思路:最直接的思路不就是 t = m; m = m*10+t 一直循環下去,直到找到答案爲止🐎,或許只有我這麼菜吧。學到一個同餘定理,也就是說我們最終答案符合標準無非就是 :

(m + m * 10 + m * 100 + …) % n == 0

但是問題就在於或許“mmmm…”的位數會很多,而且比較大的數字取模還挺費時間的,用之前那個方法我交過一次反饋是超時估計就是因爲這個吧。上述這個式子其實關注的並不是這個m最後是多少,而是我到底給這個m乘過多少次,所以它來了:

同餘定理:(m%n + m * 10%n + m * 100%n + …) % n == 0

這個乍一看還挺難以理解的,可以想像括號中的每一次取模都是除法列豎式中取餘數的操作,只不過這個被除數會會一直變大,直到有一個可以整出的數據出來豎式也就結束了。

#include <bits/stdc++.h>
using namespace std;

int _, n, digit, cas;

int main() {
	scanf("%d", &_);
	while(_--) {
		scanf("%d %d", &n, &digit);
		printf("Case %d: ", ++cas);
		int t = digit%n, ans = 1;
		while(t) {
			t = (t*10+digit)%n;
			ans++;
		}
		printf("%d\n", ans);
	}
}

Ekka Dokka

LightOJ - 1116

題意:給一個數W,需要輸出一個N,一個M;N爲奇數,M爲偶數。並且 W=NMW = N * M 。並且M需要最小。

思路:如果W給的是奇數,那麼沒有答案,奇數和偶數的乘積一定爲偶數;如果給的是偶數,如果沒有最後一個約束條件直接輸出 1 W 就完事了,那麼也就是把W中的偶數都抽出來就好了,循環除以2,抽出來的是M,剩下的是N就👌。

#include <bits/stdc++.h>
using namespace std;

int _;
long long w;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lld", &w);
		printf("Case %d: ", ++cas);
		if(w % 2) puts("Impossible");
		else {
			long long t = w;
			while(w % 2 == 0) {
				w /= 2;
			}
			printf("%lld %lld\n", w, t/w);
		}
	}
}

Mad Counting

LightOJ - 1148

題意:一個人統計鎮上有多少個人,但是他不想一個一個的去數,就想到了一個辦法,在鎮上逮到n個人👨,一個一個問“除了你自己還有多少人跟你在2010年支持的世界盃是同一個球隊”,這n個人中每個人都只會被問到一次;求鎮上最少有多少人。(爲啥他們鎮上的人這麼清楚誰支持什麼隊,我們班誰支持湖人我都不清楚)

思路:詢問的目的就是把支持同一個球隊的人給分組,比如樣例中的 1 1 2 2,詢問了四個人,第一個人表示除了他還有一個人跟他支持同一個球隊,第二個人也是這麼說,爲了讓人數最少我們可以認爲他們指的就是彼此;如果這時候再出來一個表示1的話,那麼他跟前面兩個就沒得關係了,就需要另一個隱藏的人跟他一組,所以只要有一個人說1,那麼鎮上至少就會有兩個人了。那麼同理一個人說2,就證明除了他自己還有兩個人跟他一組,後面又有一個說2,那麼爲了人口最少我們就把後面說2的加入前面說2的;如果後面又來了一個說2的那麼仍然可以加入第一個說2的那一組。規律就已經很明顯了: 說跟有i個人跟自己一樣,那麼這一組就可以加入i+1個人。往後一直讀取,滿了清零加入答案一直搞就👌

#include <bits/stdc++.h>
using namespace std;

int _, n, x;
map <int, int> a;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		a.clear();
		int ans = 0;
		scanf("%d", &n);
		printf("Case %d: ", ++cas);
		for(int i = 1;i <= n; i++) {
			scanf("%d", &x);
			if(a[x] == 0) ans += (x+1);
			a[x]++;
			if(a[x] == x+1) a[x] = 0;
		}
		printf("%d\n", ans);
	}
}

Josephus Problem

LightOJ - 1179

題意:n個人站成一個圓,1號與n號相連, 1號與2號相連的那種。從1開始報數,報到k時殺掉他,移除這個人;並從k+1個開始重新從0報數,下一個保k的繼續殺死,移除;如此循環下來,求最後一個倖存者在最開始的圓圈中的編號是多少。

思路:這是一個 約瑟夫環 的基本問題。簡單分析一下,倖存者的編號在最後剩下他的時候編號肯定是0;那麼試想一下,在還剩兩個人的時候這個倖存者的編號應該是多少纔可以倖存?因爲倖存後的他編號是1,就是從還剩兩的人的時候死了另一個後往前移動k位變成的,我們把這個k加上去後取一個當時多少人的模就可以得到當時的編號,如此往復就可以得到那個人時候這個倖存者的站位編號了。

#include <bits/stdc++.h>
using namespace std;

int _;
long long n, k;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lld %lld", &n, &k);
		printf("Case %d: ", ++cas);
		int ans = 0;
		for(int i = 2;i <= n; i++) {
			ans = (ans+k)%i;
			cout << ans+1 << endl;
		}
		printf("%d\n", ans+1);
	}
}

Internet Service Providers

LightOJ - 1275

題意:利潤 = T(CTN)T * (C - T * N) 求 使利潤最大時的最小 T

思路:整理一下式子:W=NTW = -N * T 2 +CT+ C * T 就是一個開口向下的拋物線,需要求W取最大值的時候T的值,需要注意的是在W最大的時候T可能不是整數所以需要比較一下 T 取 ans 與 ans+1 的大小。

#include <bits/stdc++.h>
using namespace std;

int _;
double n, c;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lf %lf", &n, &c);
		int ans = c/2/n;
		if(ans*(c-n*ans) < (ans+1)*(c-n*(ans+1))) ans++;
		printf("Case %d: %d\n", ++cas, n==0?0:ans);
	}
}

Positive Negative Sign

LightOJ - 1294

題意:給一個n,一個m,其中 n 可以被 2m 整除,然後有一個序列,從 1 開始一直到 n,1~m爲負號, m+1 ~ 2m爲正號,2m+1 ~ 3m 爲負號…問這樣的一個序列的和爲多少。

思路:從樣例入手 題面中給的 12 3 的序列是這樣的:

-1 -2 -3 +4 +5 +6 -7 -8 -9 +10 +11 +12

數據很大,所以枚舉或者預處理是不要想的了,規律題。看前六個數據,第一個和第四個相加爲3 也就是 m,第二個和第五個相加也是m,第三個和第六個相加仍然是m,7~12個也是這樣的規律。所以我們可以每 2*m 個數據一組,每組之和就是 m * m,再乘以組數就👌

#include <bits/stdc++.h>
using namespace std;

int _;
long long n, m;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lld %lld", &n, &m);
		printf("Case %d: ", ++cas);
		long long cnt = n/(2*m);
		long long sum = m*m;
		printf("%lld\n", sum*cnt);
	}
}

Largest Box

LightOJ - 1297

題意:一張長爲L,寬爲W 的紙,照着圖中的裁剪方式將四個角各剪出一個邊長爲x的正方形,並沿着x的邊折起來,問x取多大這個折起來的無蓋長方體的體積可以最大。

題面圖片

思路:長方體的體積表達式 V=(L2x)(W2x)xV = (L - 2 * x) * (W - 2 * x) * x

顯然是一元三次方程 展開後:

V=4xV = 4x3 2(L+W)x- 2(L+W)x2 +LWx+ LWx

求導得:

F=12xF = 12x2 4(L+W)x+LW- 4(L+W)x + LW

這個函數的圖像是這樣的 / \ / ,所以極大值在求導後爲零點的比較小的那個位置。

#include <bits/stdc++.h>
using namespace std;

int _;
double l, w;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lf %lf", &l, &w);
		double pos = (4*(l+w) - sqrt(16*(l+w)*(l+w)-4*12*l*w))/24;
		printf("Case %d: %lf\n", ++cas, (l-2*pos)*(w-2*pos)*pos);
	}
}

Unlucky Bird

LightOJ - 1311

題意:一隻鳥在兩輛相向而行的火車之間之間飛行,左邊的火車速度v1,右邊的火車速度v2,🐦的速度爲v3,這隻鳥在這兩輛車之間飛行,遇到左邊的火車時調頭向右,遇到右邊的火車調頭向左,這樣往復,當這兩輛火車距離爲d時開始減速,左邊的減速度問a1,右邊的減速度爲a2,🐦依然往復飛行,當火車距離剛好爲0的時候兩輛車的速度都是0。求d,和距離爲d之後🐦的飛行路程。

思路:物理題,注意一點就行了,兩輛火車不一定在同一時刻停車。

#include <bits/stdc++.h>
using namespace std;

int _;
double v1, v2, v3, a1, a2;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lf %lf %lf %lf %lf", &v1, &v2, &v3, &a1, &a2);
		double x1 = (v1*v1)/(2*a1);
		double x2 = (v2*v2)/(2*a2);
		double d = x1+x2; 
		double t = max(v1/a1, v2/a2);
		double fin = v3*t;
		printf("Case %d: %.8lf %.8lf\n", ++cas, d, fin);
	}
}

Billiard Balls

LightOJ - 1323

題意:一堆球在桌子上面運動,難免會碰到一起,要麼是球和球,要麼是球和桌子,題目也給出了球和球碰撞💥後的軌跡如圖:

撞擊牆面

撞擊牆面的情況

兩球相撞
兩球相撞

多求相撞

多球相撞

需要求k秒後所有球的位置,並且排序。

思路:看得出來,其實這些碰撞可以看成是沒有碰撞過,這幾個球在碰撞後走的都是對方本該走的路,那麼我們可以看成這些球都沒有收到任何影響按照自己原來的方向運動就可以了,換句話說就是因爲最後輸出並不需要每個球的編號對應所在的位置,可以忽略球之間的碰撞,考慮球與桌面的就可以了。球的運動可以分爲x方向和y方向,這個球可能走了很久以至於經過了很多次起點,那麼如果在x方向就需要對路程K % 2*L 就是球走的有效距離。再分析位於距離起點的什麼位置就好了。

#include <bits/stdc++.h>
using namespace std;

struct node {
	int x, y;
} poi[1005];

bool cmp(node a, node b) {
	if(a.x == b.x) return a.y < b.y;
	return a.x < b.x;
}

int up(int m, int l, int k) {
	int ans = k % (l*2);
	if(ans > (l-m)) {
		if(ans >= 2*l-m) {
			m = ans + m - 2*l;
		}
		else {
			m = 2*l - ans - m;
		}
	}
	else {
		m += ans;
	}
	return m;
}

int down(int m, int l, int k) {
	int ans = k % (l*2);
	if(ans > m) {
		if(ans > l+m) {
			m = 2*l - ans + m;
		}
		else {
			m = ans - m;
		}
	}
	else {
		m -= ans;
	}
	return m;
}

int main() {
	int _, cas = 0;
	scanf("%d", &_);
	while(_--) {
		int l, w, n, k;
		char a, b;
		scanf("%d %d %d %d", &l, &w, &n, &k);
		printf("Case %d:\n", ++cas);
		for(int i = 1;i <= n; i++) {
			scanf("%d %d %c %c", &poi[i].x, &poi[i].y, &a, &b);
			if(a == 'N') poi[i].y = up(poi[i].y, w, k);
			else poi[i].y = down(poi[i].y, w, k);
			
			if(b == 'E') poi[i].x = up(poi[i].x, l, k);
			else poi[i].x = down(poi[i].x, l, k);
		}
		
		sort(poi+1, poi+1+n, cmp);
		for(int i = 1;i <= n; i++) {
			printf("%d %d\n", poi[i].x, poi[i].y);
		}
	}
}

Aladdin and the Optimal Invitation

LightOJ - 1349

題意:在一個 n * m 的格子裏,每一個 (u , v) 中都有 w 個人,現在需要將格子中的所有人都聚在一個格子裏,從一個(x, y) 移動到 (p, q) 每個人需要 |x-p|+|y-q| 步,現在問最少需要多少步纔可以把所有人聚在一起,求格子的座標

思路:分別對x, y 排序, 分別找到中位數的人的座標就可以了

#include <bits/stdc++.h>
using namespace std;

int _, m, n, q;
struct node {
	int x, y, peo;
}a[50005];

bool cmp1(node p, node q) {
	return p.x < q.x;
}

bool cmp2(node p, node q) {
	return p.y < q.y;
}

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%d %d %d", &m, &n, &q);
		int sum = 0;
		for(int i = 1;i <= q; i++) {
			scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].peo);
			sum += a[i].peo;
		}
		int now = 0, ansx, ansy;
		int mid = (sum+1)/2;
		sort(a+1, a+1+q, cmp1);
		for(int i = 1;i <= q; i++) {
			now += a[i].peo;
			if(now >= mid) {
				if(sum%2) ansx = a[i].x;
				else {
					if(now == mid) ansx = (a[i].x+a[i+1].x)/2;
					else ansx = a[i].x;
				}
				break;
			}
		}
		
		now = 0;
		sort(a+1, a+1+q, cmp2);
		for(int i = 1;i <= q; i++) {
			now += a[i].peo;
			if(now >= mid) {
				if(sum%2) ansy = a[i].y;
				else {
					if(now == mid) ansy = (a[i].y+a[i+1].y)/2;
					else ansy = a[i].y;                           
				}
				break;
			}
		}
		
		printf("Case %d: %d %d\n", ++cas, ansx, ansy);
	}
}

IP Checking

LightOJ - 1354

題意: 給兩串IP地址,一串是10進制的,一串是2進制的,問這兩個IP地址是否相同

思路: 就把進制換成相同的一比就👌了

#include <bits/stdc++.h>
using namespace std;

stack <int > sta;
int _;
string a, b;
vector <int> chea, cheb;

int change(string s) {
	int n = s.length();
	int start = n;
	for(int i = 0;i < n; i++) {
		if(s[i] != 0) {
			start = i;
			break;
		}
	}
	for(int i = start; i < n; i++) sta.push(s[i]-'0');
	int t = 1, res = 0;
	while(!sta.empty()) {
		int k = sta.top(); sta.pop();
		res += (t*k); t *= 2;
	}
	return res;
}

bool check() {
	for(int i = 0;i < 4; i++) {
		if(chea[i] != cheb[i]) return 0;
	}
	return 1;
}

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		chea.clear(); cheb.clear();
		cin >> a >> b;
		int p = 0;
		for(int i = 0;i < a.length(); i++) {
			if(a[i] != '.') {
				p *= 10;
				p += (a[i]-'0');
			}
			else {
				chea.push_back(p);
				p = 0;
			} 
		}
		chea.push_back(p);
		
		p = 4;
		int head = 0;
		while(p--) {
			string q = b.substr(head, 8);
			cheb.push_back(change(q));
			head += 9;
		}
		printf("Case %d: %s\n", ++cas, check()?"Yes":"No");
	}
}

Answering Queries

LightOJ - 1369

題意:對輸入的A數組進行以下操作:

long long f( int A[], int n ) { // n = size of A

    long long sum = 0;

    for( int i = 0; i < n; i++ )

        for( int j = i + 1; j < n; j++ )

            sum += A[i] - A[j];

    return sum;

}

之後會有兩種操作

  1. 輸入 0 x y,A[x] = y
  2. 輸入1,輸出最新的sum

思路:如果按照題目中給的函數求和,那麼只是求和的時間最壞就需要100秒。所以需要另外找方法。觀察之後發現每次都是 a[i] 與後面的所有元素相減,是否可以通過預處理後面的數據進行縮短時間呢,那就需要用後綴和的辦法了,算出a[i]在當前位置有多少個會與後面的相減;O(n)的時間就可以計算出來sum。之後就是改變某一個a[i]的值,當然修改之後sum的值也需要隨之改變,也就是看 a[i] 對於在它之前的數,a[i] 充當的就是減數, 對於在a[i]之後的數充當的就是被減數,O(1)的時間就可以搞出來,就沒👌了。

#include <bits/stdc++.h>
using namespace std;

int _;
long long besum[100005], a[100005];
long long n, q, k, b, c;

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%lld %lld", &n, &q);
		for(int i = 0;i < n; i++) {
			scanf("%lld", &a[i]);
		}
		
		besum[n-1] = a[n-1];
		for(int i = n-2;i >= 0; i--) {
			besum[i] = besum[i+1] + a[i];
		}
		
		long long sum = 0;
		for(int i = 0;i < n-1; i++) {
			sum += (a[i]*(n-1-i)-besum[i+1]);
		}
				
		printf("Case %d:\n", ++cas);
		
		while(q--) {
			scanf("%lld", &k);
			if(k == 1) {
				printf("%lld\n", sum);
			} 
			else {
				scanf("%lld %lld", &b, &c);
				long long t = c-a[b];
				a[b] = c;
				sum = sum - t*b + t*(n-b-1);
			}
		}
    
	}
}

Consistent Verdicts

LightOJ - 1410

題意:在一個平面上有N個人,每個人的聽力範圍都相同但未知,現在每個人都在自己的點開槍,在與他距離在聽力範圍內的人都聽到槍聲,求在每個人開一遍槍之後每個人聽到多少聲的槍響的可能組合的數量。

思路:有多少種不同的距離就是解的數量

#include <bits/stdc++.h>
using namespace std;

int _, n;
long long x[705], y[705], dis[500000];

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%d", &n);
		for(int i = 1;i <= n; i++) {
			scanf("%lld %lld", &x[i], &y[i]);
		}
		
		int cnt = 0;
		for(int i = 1;i <= n; i++) {
			for(int j = i+1;j <= n; j++) {
				dis[++cnt] = (x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
			}
		}
		
		sort(dis+1, dis+1+cnt);
		int num = unique(dis+1, dis+1+cnt) - dis;
		printf("Case %d: %d\n", ++cas, num);
	}
}

February 29

LightOJ - 1414

題意:給出兩個年月日,算這個時間區間裏面有多少個2月29號。

思路:閏年定義就不說了。衆所周知,一個數除以另一個數就可以算出被除數中包含多少個除數,這個題目也就是這個思路,大年份減小年份再除以需要除的數就可以 算出 (小年份, 大年份] 之間包含的除數。

用這個思路求出 年份之間的 可以整除 4 的年份個數, 可以整除 400 的年份個數, 可以整除100 的年份個數。前兩個相加再減去第三個就可以得到一個近似答案了。

然後再討論這兩個邊界年份,小年份如果是閏年並且日期早於 2月29日 答案就需要+1;大年份如果是閏年,但是日期早於 2月29日 那麼答案需要 -1;最後就可以輸出了。

#include <bits/stdc++.h>
using namespace std;

int _;
string month1, day1, month2, day2;
long long year1, year2;
map <string, int> mon;

void init() {
	mon["January"] = 1; mon["February"] = 2; mon["March"] = 3;
	mon["April"] = 4; mon["May"] = 5; mon["June"] = 6; 
	mon["July"] = 7; mon["August"] = 8; mon["September"] = 9; 
	mon["October"] = 10; mon["November"] = 11; mon["December"] = 12;
}

bool check(long long year) {
	if(year % 100 == 0) {
		if(year % 400 == 0) return 1;
		else return 0;
	}
	else if(year % 4 == 0) return 1;
	else return 0;
}

int main() {
	init();
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		cin >> month1 >> day1 >> year1;
		cin >> month2 >> day2 >> year2;
		printf("Case %d: ", ++cas);
		
		int ans = (year2/4-year1/4) + (year2/400-year1/400) - (year2/100-year1/100);
		if(check(year1) && mon[month1] <= 2) ans++;
		if(check(year2) && !(mon[month2] >= 3 || (mon[month2] == 2 && day2 == "29,"))) ans--;
		
		printf("%d\n", ans);
	}
}

Eid

LightOJ - 1024

題意: 求最小公倍數

思路:數據很大,需要Java大數來做

import java.util.Scanner;
import java.math.BigInteger;

class Main {
	public static void main(String[] args) {
		Scanner input = new Scanner(System.in);
		int t = input.nextInt();
		for(int tt = 1;tt <= t; tt++) {
			int n = input.nextInt();
			BigInteger ans, m, k;
			m = input.nextBigInteger();
			ans = m;
			for(int i = 1;i < n; i++) {
				m = input.nextBigInteger();
				k = ans.gcd(m);
				ans = ans.multiply(m).divide(k);
			}
			System.out.println("Case "+ tt + ": " + ans);
			System.gc();
		}
	}
}

Monkey Tradition

LightOJ - 1319

題意:N個🐒爬N個長爲L的竹竿,每個🐒每個單位時間爬的高度不一樣,最後就會有長度長度剩餘,因爲不夠🐒一次爬的嘛,就根據這些不同的剩餘長度,求L(🐒單位時間爬的高度都是質數)。

思路:中國剩餘定理,可以一下。

#include <bits/stdc++.h>
using namespace std;

long long m[20], a[20];
int _, n;

void exgcd(long long a, long long b, long long &x, long long &y) {
	if(!b) {
		x = 1;
		y = 0;
	}
	else {
		exgcd(b, a%b, y, x);
		y -= (a/b) * x;
	}
}

long long CRT() {
	long long M = 1;
	for(int i = 1;i <= n; i++) M *= m[i];
	long long ans = 0;
	for(int i = 1;i <= n; i++) {
		long long x, y, Mi;
		Mi = M/m[i];
		exgcd(Mi, m[i], x, y);
		ans = (ans + a[i]*Mi*x) % M;
	}
	
	if(ans < 0) ans += M;
	return ans;
}

int main() {
	scanf("%d", &_);
	int cas = 0;
	while(_--) {
		scanf("%d", &n);
		for(int i = 1;i <= n; i++) {
			scanf("%lld %lld", &m[i], &a[i]);
		}
		printf("Case %d: %lld\n", ++cas, CRT());
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章