日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU 5514Frogs

發(fā)布時間:2023/12/8 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU 5514Frogs 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原題傳送門

題意:

有n只青蛙,m塊石頭呈環(huán)放置(從0~m-1標(biāo)記),第i只青蛙每次跳ai步,跳躍次數(shù)無限制。求被n只青蛙踩過的石頭的下表和

思路1(歐拉函數(shù)):

很明顯,對于第i只青蛙,被踩的石頭的編號一定是gcd(ai, m)的倍數(shù),那么我們先將ai轉(zhuǎn)換為gcd(ai,m)
然后對于第 j 塊石頭,我們定義它只能被跳躍步數(shù)為x的青蛙踩中(x滿足gcd(m,j)= x)例如下面的樣例:

2 12
9 10
那么這個樣例之中被踩過并且有貢獻(xiàn)的石頭編號為2,3,4,6,8,9,10
按照我們的定義
2 10 是被跳躍步數(shù)為2的青蛙踩過
3 9 是被跳躍步數(shù)為3的青蛙踩過
4 8 是被跳躍步數(shù)為4的青蛙踩過
6 是被跳躍步數(shù)為6的青蛙踩過

這里的青蛙只有兩個,但是我們可以造兩個步數(shù)為4 和 6的青蛙,這對答案是完全沒有影響的
因此 x 的答案貢獻(xiàn)為 m以內(nèi) j [gcd(m,j)== x]
由gcd(m,j)= x,可以得到gcd(m/x,j/x)= 1,即(j/x)為(m/x)內(nèi)所有與(m/x)互素的數(shù)
那么上面對于x的答案貢獻(xiàn)就轉(zhuǎn)換為 x * i [gcd(m/x,i)== 1]

知識點:設(shè)小于n的所有與n互質(zhì)的數(shù)的和為Sum,Sum=n?φ(n)/2

證明:
1. gcd(x,n)= 1,那么gcd(n-x,n)= 1同樣滿足
2. 可見n以內(nèi)與n互素的數(shù)字都是成對出現(xiàn)的,而素數(shù)對的個數(shù)就是φ(n)/2,并且每一對素數(shù)和為n
證畢

由此x的答案再次變換為

x *(φ(m/x)/ 2 *(m/x))

稍稍化簡得到

φ(m/x)/ 2*m

到這里就可以直接枚舉m的因子,看跳躍步數(shù)為當(dāng)前的因子fac青蛙能否被構(gòu)造(fac % ai == 0)即可

AC代碼1:

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e4 + 9;int a[N], fac[N];int Euler (int n) {ll res = n;for (int i = 2; i * i <= n; i++) {if (n % i == 0) {res = res / i * (i - 1);while (n % i == 0) {n /= i;}}}if (n > 1) {res = res / n * (n - 1);}return res; }int get_fac(int n) {int len = 0;for (int i = 2; i * i <= n; i ++) {if (n % i == 0) {fac[len++] = i;if (i * i != n) {fac[len++] = n / i;}}}sort (fac, fac + len);return len; }int main() {int T, cnt = 1;scanf ("%d", &T);while (T --) {int n, m;bool flag = false;scanf ("%d%d", &n, &m);int len = get_fac(m);for (int i = 0; i < n; i ++) {scanf ("%d", a + i);a[i] = __gcd(a[i], m);if (a[i] == 1) {flag = true;}}ll ans = 0;for (int i = 0; i < len; i ++) {for (int j = 0; j < n; j ++) {if (fac[i] % a[j] == 0) {ans += 1ll * Euler(m/fac[i]) * m / 2 ;break;}}}printf ("Case #%d: ", cnt ++);if (flag) {cout << 1ll * m * (m - 1) / 2 << endl;} else {cout << ans << endl;}}return 0; }

思路2(容斥原理):

首先預(yù)處理出m的所有因子,每個因子的答案貢獻(xiàn)次數(shù)初始化為1,然后根據(jù)容斥原理去調(diào)節(jié)后續(xù)每個因子的答案貢獻(xiàn)次數(shù)。例如下面的樣例:

2 24
9 10
24的所有因子為 2,3,4,6,8,12

初始化所有因子的答案貢獻(xiàn)為1
計算2的答案貢獻(xiàn)的時候,2的答案貢獻(xiàn)次數(shù)為1,因此4,6,8,12的答案貢獻(xiàn)次數(shù) -1
計算3的答案貢獻(xiàn)的時候,3的答案貢獻(xiàn)次數(shù)為1,6和12的答案貢獻(xiàn)次數(shù)-1
計算4的答案貢獻(xiàn)的時候,4的答案貢獻(xiàn)次數(shù)為1,8和12的答案貢獻(xiàn)次數(shù)-1
(!高潮來了!)
計算6的答案貢獻(xiàn)的時候,答案貢獻(xiàn)次數(shù)為-1,這個時候12的答案貢獻(xiàn)次數(shù) -(-1)也就是+1
計算8的答案貢獻(xiàn)的時候,答案貢獻(xiàn)次數(shù)為-1,后續(xù)因子沒有8的倍數(shù),因此無須調(diào)節(jié)其他因子的答案貢獻(xiàn)次數(shù)
計算12的答案貢獻(xiàn)的時候,答案貢獻(xiàn)次數(shù)為-1,與上面同理
(容斥原理真奇妙)

AC代碼2:

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e4 + 9;int a[N], vis[N], fac[N];int init(int n) {memset (vis, 0, sizeof vis);int len = 0;for (int i = 2; i * i <= n; i ++) {if (n % i == 0) {fac[len++] = i;if (i * i != n) {fac[len++] = n / i;}}}sort (fac, fac + len);return len; }int main() {int T, cnt = 1;scanf ("%d", &T);while (T --) {int n, m;bool flag = false;scanf ("%d%d", &n, &m);int len = init(m);for (int i = 0; i < n; i ++) {scanf ("%d", a + i);a[i] = __gcd(a[i], m);if (a[i] == 1) {flag = true;}for (int j = 0; j < len; j ++) {if (fac[j] % a[i] == 0) {vis[j] = 1;}}}ll ans = 0;for (int i = 0; i < len; i ++) {ll res = m / fac[i];ans += res * (res - 1) / 2 * fac[i] * vis[i];for (int j = i + 1; j < len; j ++) {if (fac[j] % fac[i] == 0) {vis[j] -= vis[i];}}}printf ("Case #%d: ", cnt ++);if (flag) {cout << 1ll * m * (m - 1) / 2 << endl;} else {cout << ans << endl;}}return 0; }

(PS.以上的答案貢獻(xiàn)計算都是O(1)的)

總結(jié)

以上是生活随笔為你收集整理的HDU 5514Frogs的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。