問題蟲洞——C: C - Aladdin and the Flying Carpet
黑洞內窺:
給你兩個數n、k, 求大於k的n的約數的個數
思維光年:
一個基礎知識:合數的正因素個數公式
(1)一個大於1的正整數N,如果它的標準分解式爲:,那麼它的正因數個數爲。
然後減去小於k的約數,,搞定。
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 1000005
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000000007;
bool is[MAXN];
int prime[MAXN];
ll tot;
void getprime() //歐拉篩
{
memset(is, false, sizeof(is));
tot = 0;
for(int i=2; i<=MAXN; ++i)
{
if(is[i] == false)
prime[tot++] = i;
for(int j=0; j<tot && i*prime[j] <= MAXN; ++j)
{
is[i*prime[j]] = true;
if(i%prime[j] == 0)
break;
}
}
}
ll solution(ll n)
{
ll ans = 1;
for(int i=0; i<tot && prime[i] < n; ++i)
{
int k = 0;
while(n%prime[i] == 0)
{
n/=prime[i];
++k;
}
ans*=(1+k);
}
if(n > 1)
ans*=2;
return ans;
}
int main()
{
getprime();
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, m, sum=0, ans;
scanf("%lld %lld", &n, &m);
if(m*m > n)
ans = 0;
else
{
for(int i=1; i<m; ++i)
if(n%i == 0)
sum++;
ans = solution(n)/2 - sum;
}
printf("Case %d: %lld\n", ccc++, ans);
}
return 0;
}
問題黑洞——D: D - Sigma Function
黑洞內窺:
設一個函數f(n) = n 的所有約數的和,如 f(6) = 1+2+3+6 = 12
給出一個數n,求1~n中f(x) 爲偶數的個數。
思維光年:
一個基礎知識:約數和公式:
對於已經分解的整數A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)
有A的所有因子之和爲
S = (1+p1+p1^2+p1^3+...p1^k1) * (1+p2+p2^2+p2^3+….p2^k2) * (1+p3+ p3^3+…+ p3^k3) * .... * (1+pn+pn^2+pn^3+...pn^kn)
(2) 它的全體正因數之和爲
我能想到的就只有暴力和唯一分解式的約數和公式了。。。
理性的思考:
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 5000
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
int main()
{
int t, ccc=1;
cin >> t;
while(t--)
{
ll n;
scanf("%lld", &n);
ll a = sqrt(n);
ll b = sqrt(n/2);
printf("Case %d: %lld\n", ccc++, n-a-b);
}
return 0;
}
問題蟲洞——E: E - Leading and Trailing
黑洞內窺:
求n^k 的前三位數,和後三位數。
(注意,如果答案不夠三位數,則在前面補0)
思維光年:
後三位:快速冪取模1000
前三位:log(10爲底)取模,,,,設f(n) = n^k,
則x = log f(n) = k * log( n ) , 設x = a(整數部分) + b(小數部分)
則10^(a+b) = n ^ k, 我們知道10^a 爲10 的整數冪次,是無法提取出有效數字的,
所以我們要的是10^b,,,,,然後再擴大到所需的三位數即可;
(好像在哪裏做過。。。。有點熟悉)
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 5000
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000;
const double eps = 0.0000001;
int ksm(ll a, ll b)
{
a%=mod;
ll ans = 1;
while(b)
{
if(b&1)
ans = ans*a%mod;
a = a*a%mod;
b >>= 1;
}
return (int)ans;
}
int fir(ll n, ll k)
{
double ans = k*log10(1.0*n);
ans -= floor(ans); //去小數部分b
ans = pow(10, ans);
while(ans < 100)
ans*=10;
return (int)ans;
}
int main()
{
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, k;
scanf("%lld %lld", &n, &k);
printf("Case %d: %.3d %.3d\n",ccc++, fir(n, k), ksm(n, k));
}
return 0;
}
問題蟲洞——F: F - Goldbach`s Conjecture
黑洞內窺:
給出數n, 求有多少對質數和等於n。
思維光年:
打表+暴力
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 10000010
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const int mod = 1000;
const double eps = 1e-6;
bool is[MAXN];
int prime[1000000];
ll tot, n;
void getprime() //歐拉篩
{
memset(is, false, sizeof(is));
tot = 0;
for(int i=2; i<=MAXN; ++i)
{
if(is[i] == false)
prime[tot++] = i;
for(int j=0; j<tot && i*prime[j] <= MAXN; ++j)
{
is[i*prime[j]] = true;
if(i%prime[j] == 0)
break;
}
}
}
int main()
{
getprime();
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, sum=0;
scanf("%lld", &n);
for(int i=0; i<tot && prime[i] <= n/2; ++i)
{
if(is[n - prime[i]] == false)
sum++;
}
printf("Case %d: %d\n",ccc++, sum);
}
return 0;
}
問題蟲洞——G: G - Harmonic Number (II)
黑洞內窺:
定義一個函數:f(n) = n/1 + n/2 + n/3 +.........+ n/n-1 + n/n;
給出n, 求f(n),
思維光年:
直接做會t:
參考一下這篇博客:居然。。。。B - Number of Containers
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 10000010
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const int mod = 1000;
const double eps = 1e-6;
int main()
{
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, sum=0;
scanf("%lld", &n);
int c = sqrt(n);
for(int i=1; i<=c; ++i)//梯形面積
sum+=n/i;
sum*=2;
sum = sum-c*c;
printf("Case %d: %lld\n",ccc++, sum);
}
return 0;
}
問題蟲洞——H: H - Pairs Forming LCM
黑洞內窺:
給你一個數n, 求有多少對(i, j) 的最小公倍數(lcm(i, j) == n) 爲n
思維光年:
一個基礎知識:
對a,b求唯一分解式:
a=p1 ^ a1 * p2 ^ a2 *..........*pn ^ an
b=p1 ^ b1 * p2 ^ b2 *..........*pn ^ bn
gcd(a,b)=p1 ^ min(a1,b1) * p2 ^ min(a2,b2) *..........*pn ^ min(an,bn)
lcm(a,b)=p1 ^ max(a1,b1) * p2 ^ max(a2,b2) *..........*pn ^ max(an,bn)
get到一項求gcd、lcm的技能沒u有?!
理性的求解:
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 10000010
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const int mod = 1000;
const double eps = 1e-6;
bool is[MAXN];
int prime[1000000];
ll tot, n;
void getprime() //歐拉篩
{
memset(is, false, sizeof(is));
tot = 0;
for(int i=2; i<=MAXN; ++i)
{
if(is[i] == false)
prime[tot++] = i;
for(int j=0; j<tot && i*prime[j] <= MAXN; ++j)
{
is[i*prime[j]] = true;
if(i%prime[j] == 0)
break;
}
}
}
ll fenjie(ll s)
{
ll n = s;
ll sum = 1;
for (int i = 0; i < tot && prime[i]*prime[i] <= n; ++i)
{
if(n%prime[i] == 0)
{
int k=0;
while (n % prime[i] == 0)
{
n /= prime[i];
k++;
}
sum*=(2*k+1);
}
}
if (n > 1)
sum*=3;
return sum;
}
int main()
{
getprime();
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, sum=0;
scanf("%lld", &n);
sum = fenjie(n);
printf("Case %d: %lld\n",ccc++, (sum+1)/2);
}
return 0;
}
問題蟲洞——I: I - Harmonic Number
參考博客:Harmonic Number(調和級數)
問題蟲洞——J: J - Mysterious Bacteria
黑洞內窺:
給出一個數x, 設x可以表示爲 x = b^p, 求p的最大值。(x <= 2^32, x可正可負)
思維光年:
我的思路:
既然x是小於2的32次方的,直接暴力開方跑唄,反正最差也就32次。。。。
但可能因爲是pow的精度還是double的精度問題,導致我一直wa。。。。
後來就去搜題解了。。。
理性的求解:
求x,和b的唯一分解式,則有:
x=p1^x1 p2 ^x2 …. pk^xk
b=p1^b1 p2^b2…..pk^bk
題意給出關係,x = b^p,所以:
b1*p=x1
b2*p=x2
. .. . . .
bk*p=xk
想要讓式子同時成立,則有 p | gcd(x1,x2,x3...xk) 。
所以 ,現在讓求最大,如果x爲正數,p=gcd(x1,x2,x3...xk)
否則 p 就是gcd(x1,x2,x3,,,xk) 的最大奇數因子。
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 100010
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const int mod = 1000;
const double eps = 1e-6;
ll prime[MAXN], tot, ans;
bool is[MAXN];
void getprime()
{
memset(is, false, sizeof(is));
tot = 0;
for(int i=2; i<=MAXN; ++i)
{
if(is[i] == false)
prime[tot++] = i;
for(int j=0; j<tot && i*prime[j] <= MAXN; ++j)
{
is[i*prime[j]] = true;
if(i%prime[j] == 0)
break;
}
}
}
ll gcd(ll a, ll b)
{
return b == 0? a: gcd(b, a%b);
}
int main()
{
getprime();
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, sum=0, flag = 0;
scanf("%lld", &n);
if(n < 0)
{
n = -n;
flag = 1;
}
for(int i=0; i<tot && prime[i] <= n; ++i)
{
if(n%prime[i] == 0)
{
int ans = 0;
while(n%prime[i] == 0)
{
n/=prime[i];
ans++;
}
if(sum) sum = gcd(sum, ans);//求最大公約數
else sum = ans;
if(sum == 1) break;
}
}
if(n>1) sum = 1;
if(flag && sum%2 == 0)
{
while(sum%2 == 0)
sum/=2;
}
printf("Case %d: %lld\n",ccc++, sum);
}
return 0;
}
一開始wa的代碼:(給大家批鬥批鬥。。。[如果有人指教一下就更好啦,,啦啦啦啦啦,,,,])
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 10000010
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const int mod = 1000;
const double eps = 1e-6;
int main()
{
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, sum=1, flag = 0;
scanf("%lld", &n);
if(n < 0)
{
flag = 1;
n = -n;
}
for(ll i=2; i<=32; ++i)
{
if(flag && i%2 == 0) continue;
double s = pow(n, double(1.0/i));
int ans = ceil(pow(floor(s), i));
if(s <= 1)
break;
if(ans == n)
sum = max(sum, i);
}
printf("Case %d: %lld\n",ccc++, sum);
}
return 0;
}
問題蟲洞——K: K - Large Division
黑洞內窺:
給你兩個大數a, b, 問 a|b?,,
思維光年:
問題可轉換成 a%b == 0?
然後就是一個大數取模。。
兩分鐘代碼,十分鐘bug,,,,
我現在是知道了string中的earse不能直接用成s.earse(0) , 括號裏面的東西是string的迭代器
所以你要改成,,,s.earse(s.begin() + i) ,刪除第i個元素。。。
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 5000
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
string s;
int main()
{
int t, ccc=1;
cin >> t;
while(t--)
{
ll b;
cin >> s >> b;
if(s[0] == '-') s.erase(s.begin());//這裏是坑。。。
if(b<0) b = -b;
int len = s.size();
ll sum = 0;
for(int i=0; i<len; ++i)
{
sum*=10;
sum+=(s[i] - '0');
if(sum >= b) sum%=b;
}
printf("Case %d: ", ccc++);
if(sum) puts("not divisible");
else puts("divisible");
}
return 0;
}
問題蟲洞——L: L - Fantasy of a Summation
黑洞內窺:
輸入n,k,mod,再輸入n個數ai,
求在k重循環下的(0~n-1的ai)求和取模
思維光年:
多列幾項就可以發現規律了;
答案 = n^(k-1)*k*sum%mod;
(其中sum爲ai的求和)
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
#define MAXN 5000
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
ll ksm(ll a, ll b, ll md)
{
ll ans = 1;
while(b)
{
if(b&1)
ans = ans*a%md;
a = a*a%md;
b >>= 1;
}
return ans;
}
int main()
{
int t, ccc=1;
cin >> t;
while(t--)
{
ll n, k, m, x, sum=0;
cin >> n >> k >> m;
for(int i=0; i<n; ++i)
{
scanf("%lld", &x);
sum+=x;
}
sum = ksm(n, k-1, m)*k%m*sum%m;
printf("Case %d: %lld\n", ccc++, sum);
}
return 0;
}
問題蟲洞——M: M - Help Hanzo
黑洞內窺:
求區間[a, b]中的素數個數,,,,(b-a <= 100000)
思維光年:
區間素數篩。。。。。
wa到我想si~~~~~~
由於區間比較小,所以我們可以直接求一個區間的素數
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
const ll MAXN = 100005;
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
int prime[MAXN], tot, ans;
bool is[MAXN], vis[MAXN];
void getprime()
{
memset(is, false, sizeof(is));
tot = 0;
is[0] = is[1] = true;
for(int i=2; i<=MAXN; ++i)
{
if(is[i] == false)
prime[tot++] = i;
for(int j=0; j<tot && i*prime[j] <= MAXN; ++j)
{
is[i*prime[j]] = true;
if(i%prime[j] == 0)
break;
}
}
}
int main()
{
getprime();
int t, ccc=1;
cin >> t;
while(t--)
{
ll a, b, sum=0;
cin >> a >> b;
if(b <= MAXN)
{
for(ll i=a; i<=b; ++i)
if(!is[i])
sum++;
}
else
{
memset(vis, 0, sizeof(vis)); //維護區間
for(int i=0; i<tot && prime[i]*prime[i] <= b; ++i)
{
ll k = ceil(a*1.0/prime[i]);
for(ll j = k*prime[i]; j<=b; j+=prime[i])
vis[j-a] = true;
}
for(ll i=a; i<=b; ++i)
if(!vis[i-a])
sum++;
}
printf("Case %d: %lld\n", ccc++, sum);
}
return 0;
}
問題蟲洞——N: N - Trailing Zeroes (III)
黑洞內窺:
給出數字q,求一個數n,
該數滿足條件:n!尾數有q個0;
思維光年:
思維+二分。。
尾數如果要出現0, 就必須是2*5, 而在n!中2的因子個數必然多於5
所以,題目等同於,求有q個因子是5的數n!。
我一開始是做對了的啊,,,wawawawawawa,,,
明明就是PE,你一wa我還以爲思路有問題。。。
枯了~~~~~~~~;
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
const ll MAXN = 500000000;
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
ll SUM(ll n)
{
return n == 0? 0: n/5+SUM(n/5);
}
int main()
{
int t, ccc=1;
//cout << SUM(500000000) << '\n';
cin >> t;
while(t--)
{
ll n, sum = -1;
scanf("%lld", &n);
ll l=0,r = MAXN;
while(l <= r) //這裏不能特判相等,雖然結果是對的,但不能AC
{
ll m = (l+r)/2;
if(SUM(m) >= n)
r = m-1;
else
l = m+1;
}
if(SUM(l) == n)
printf("Case %d: %lld\n", ccc++, l);
else
printf("Case %d: impossible\n", ccc++);
}
return 0;
}
問題蟲洞——O: O - GCD - Extreme (II)
黑洞內窺:
給出數n,求
思維光年:
理所當然的想到了歐拉函數,,,,
理性的求解:
歐拉函數:滿足 0<x<n 且 gcd(x,n) = 1 的x有phi[n]個。
可以推論出:滿足 0<2*x<2*n 且 gcd(2*x,2*n) = 2 的2*x同樣有phi[n]個,
推向一般:滿足 0<k*x<k*n 且 gcd(k*x,k*n) = k 的k*x有euler[n]個。
其實就是對於n來說,在1~n-1內與它互質的數都乘上相應的倍數,同時n也乘上相應的倍數,因而他們的最大公約數也爲乘上的倍數,但不管如何,個數沒有改變,仍爲euler[n]個,只不過是他們的值“放大”了而已。
最後,就可以枚舉每個歐拉函數phi[n]和係數k,然後進行統計。
ACcode:
//#include<bits/stdc++.h>
#include <stdio.h>
#include <iostream>
#include<algorithm>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <stdlib.h>
#include <cstring>
#include <string.h>
#include <string>
#include <math.h>
#include <sstream>
using namespace std;
typedef long long ll;
const ll MAXN = 4000009;
#define INF 0x3f3f3f3f//將近ll類型最大數的一半,而且乘2不會爆ll
const ll mod = 1000000007;
const double eps = 0.0000001;
int phi[MAXN]; //歐拉函數
void getphi()
{
phi[1] = 1;
for(int i=2; i<MAXN; ++i)
{
if(!phi[i])
{
for(int j=i; j<MAXN; j+=i)
{
if(!phi[j]) phi[j] = j;
phi[j] = phi[j]/i*(i-1);
}
}
}
}
ll a[MAXN];
void init()
{
for(int i=2; i<MAXN; ++i) //枚舉單位歐拉數
for(int k=1; k*i < MAXN; ++k) //枚舉倍數
a[i*k]+=k*phi[i]; //累加倍數gcd
for(int i=2; i<MAXN; ++i)
a[i]+=a[i-1];
}
int main()
{
getphi();
init();
int n;
while(cin >> n && n)
cout << a[n] << '\n';
return 0;
}