题目1:Leading and Trailing
分析:
本题求n的k次方的前三位和后三位
1)后三位较为好求,快速幂不断%1000即可
2)前三位:推导公式
n
k
n^k
nk =
1
0
p
10^p
10p (p为double)
(取log) => k
l
o
g
n
log{n}
logn = p
设y = p - (int)p
则
1
0
y
10^y
10y即为所求
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1000;
const int maxn = 2e6;
const int inf = 0x3f3f3f3f;
ll qpow(ll a, ll n)
{
ll res = 1;
while(n)
{
if(n & 1) res = res * a % mod;
a = a * a % mod;
n >>= 1;
}
return res;
}
int main()
{
int t; cin >> t;
int cases = 0;
while(t--)
{
ll n, k; cin >> n >> k;
double p = 1.0 * k * log10(double(n));
ll x = 1.0 * k * log10(double(n));
double y = p - x;
ll res1 = 100.0 * pow(10, y);
ll res2 = qpow(n, k);
printf("Case %d: %03lld %03lld\n", ++cases, res1, res2);
}
}
题目2:因数个数和
给个n,求1到n的所有数的约数个数的和~
做法一:分块
ll solve(ll n){
ll ans = 0;
for(ll l = 1,r;l <= n;l = r + 1){
r = n / (n / l); //l-r的中数贡献了相同数量的约数,因而可以通过分块批量求
ans += (r-l+1)*(n/l);
}
return ans;
}
分析:
代码:
#include<stdio.h>
#include<math.h>
int main() {
int t;
scanf("%d",&t);
int n;
while(t--) {
int i;
int t;
long long sum=0;
scanf("%d",&n);
t=(int)sqrt((double)n);
for(i=1;i<=t;i++)
sum+=(n/i);
sum*=2;
sum=sum-t*t;
printf("%lld\n",sum);
}
return 0;
}
题目3:Harmonic Number LightOJ - 1234
分析:
神奇打表:小数打表,大数套公式
H
n
=
l
o
g
n
+
1
/
(
2
∗
n
)
+
C
H_n=logn+1/(2 *n) +C
Hn=logn+1/(2∗n)+C(C为欧拉常数,详见代码)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const double gama = 0.57721566490153286060651209;
const ll mod = 1e9 + 7;
const int maxn = 2e6;
const int inf = 0x3f3f3f3f;
double sum[maxn];
void make()
{
double s = 0;
for(int i = 1; i < maxn; i++)
s += 1.0 / i, sum[i] = s;
}
int main()
{
make();
int t, cases = 0; cin >> t;
while(t--)
{
int n; cin >> n;
double res;
if(n < maxn) res = sum[n];
else res = log(double(n)) + 1.0 / (2 * n) + gama;
printf("Case %d: %.10lf\n", ++cases, res);
}
}
题目4:Harmonic Number (II) LightOJ - 1245
分析:
暴力肯定超时,不妨换个角度——顺瓜摸藤:枚举商
通过分析,商最大为sqrt(n)
枚举商(除数)时,对于除数,直接计算即可,对于商,则需先计算出这个商出现了多少次,在乘以商的值即为贡献。
最后计算完成后扣除重复计算的部分
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1e9 + 7;
const int maxn = 2e6;
const int inf = 0x3f3f3f3f;
int main()
{
int t; cin >> t;
int cases = 0;
while(t--)
{
ll n; cin >> n;
ll sum = 0;
for(int i = 1; i <= sqrt(n); i++)
{
sum += n / i;
sum += (n / i - n / (i + 1)) * i;
}
if(n / (ll)sqrt(n) == (ll)sqrt(n)) sum -= (ll)sqrt(n);
printf("Case %d: %lld\n", ++cases, sum);
}
}
题目6:Trailing Zeroes (III) LightOJ - 1138 思维+二分
分析:
我们知道零是由10决定的,10可以分解为素数2和5,而2的数量大于5,根据木桶定理,零的个数就是1-n中5的个数。5含有1个5,10含有一个5,25含有两个5,那么n可能是大于等于5,小于等于5*q,以此为界限进行二分即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1e9 + 7;
const int maxn = 2e6;
const int inf = 0x3f3f3f3f;
ll calc(ll n)
{
ll res = 0;
while(n)
{
res += n;
n /= 5;
}
return res;
}
int main()
{
int cases = 0;
int t; cin >> t;
while(t--)
{
ll n; cin >> n;
int flag = 0;
ll l = 1, r = n;
ll mid;
while(l <= r)
{
mid = l + r >> 1;
ll ans = calc(mid);
if(ans == n)
{
flag = 1;
break;
}
else if(ans < n) l = mid + 1;
else r = mid - 1;
}
if(flag) printf("Case %d: %lld\n", ++cases, mid * 5);
else printf("Case %d: impossible\n", ++cases);
}
}
题目7:The Super Powers UVA - 11752
分析:
这个题主要是注意上限是
2
64
−
1
2^{64}-1
264−1,所以我们需要用unsigned long long.
为了防止ull溢出,我们在枚举的时候需要通过log设置判断条件:
for(int i = 2; i < 65536; i++)
{
for(int j = 4; j <= 64 && j < 64 * log(2) / log(i); j++)
{
if(vis[j]) res.insert(qpow(i, j));
}
}
数学推导为:
i
j
<
2
64
i^j < 2^{64}
ij<264
j < 64log2 / logi
代码:
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
//typedef __int128 lll;
#define print(i) cout << "debug: " << i << endl
#define close() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define mem(a, b) memset(a, b, sizeof(a))
const ll mod = 1e9 + 7;
const int maxn = 1e5;
const int inf = 0x3f3f3f3f;
int vis[maxn];
vector<int> p;
set<ll> res;
void make()
{
for(int i = 2; i < maxn; i++)
if(!vis[i])
{
for(int j = i * 2; j < maxn; j += i)
vis[j] = 1;
}
}
ll qpow(ll a, ll n)
{
ll res = 1;
while(n)
{
if(n & 1) res *= a;
a *= a, n >>= 1;
}
return res;
}
int main()
{
make();
res.insert(1);
for(int i = 2; i < 65536; i++)
{
for(int j = 4; j <= 64 && j < 64 * log(2) / log(i); j++)
{
if(vis[j]) res.insert(qpow(i, j));
}
}
for(auto it : res)
cout << it << endl;
}
题目8:
分析:
代码: