零碎知識點
- 計算最大公約數(輾轉相除法或歐幾里得算法)
int gcd(int a, int b){
return b==0?a:gcd(b, a%b);
}
- 計算最小公倍數:lcm(a, b) = a/gcd(a, b) * b。一定寫成先除後乘,如果寫成ab/gcd(a, b),那麼ab可能會溢出。
- Eratosthenes篩法
int isprime[MAX];
void eratos(int n)//埃拉托色尼篩選法
{
memset(isprime, 0, sizeof(isprime));
int m = sqrt(n+0.5);
for(int i=2; i<=m; i++)
{
if(isprime[i]==1) continue;
//技巧,i*k(k<i)一定已經被標記過了
for(int j=i*i; j<=n; j+=i)
{
isprime[j] = 1;
}
}
}
- 擴展歐幾里得算法
void exgcd(int a, int b, int &d, int &x, int &y){
if(!b){
d = a;
x = 1;
y = 0;
}
else{
gcd(b, a%b, d, y, x);
y -= x*(a/b);
}
}
int extend_ojld(int a, int b, int &x, int &y)
{
int d;
if(b == 0)
{
d = a;
x = 1;
y = 0;
}
else
{
d = extend_ojld(b, a%b, y, x);
y -= (a / b) * x;
}
return d;
}
- int、long long的取值範圍:
題目名稱 | 題目類型 | 對應符號 |
---|---|---|
unsigned int | 0~4294967295 (10位數,4e9) | %u |
int | -2147483648~2147483647 (10位數,2e9 2^31 - 1) | %d |
long long | -9223372036854775808~9223372036854775807 (19位數, 9e18 ) 2^63 - 1 | %lld |
unsigned long long | 0~18446744073709551615 (20位數,1e19) 2^64 - 1 | %llu |
- ^是異或運算符。
- 唯一分解定理:
- 先算出範圍內的素數,再分解。
const int maxn=10000+5;
int e[maxn]; //用e[]保存每一位素數的指數
vector<int> primes;//存儲範圍內所有指數
void GetPrime()//獲得範圍的所有的素數
{
int n[10000]={0};
for(int i=2;i<=sqrt(10000+0.5);i++)
{
if(!n[i])
{
for(int j=i*i;j<=10000;j+=i) n[j]=1;
}
}
for(int i=2;i<=10000;i++)
{
if(!n[i]) primes.push_back(i);
}
}
void add_int(int n,int d)
{
for(int i=0;i<primes.size()&&n!=1;i++)
{
while(n%primes[i]==0) {
n/=primes[i];
e[i]+=d;
}
}
}
- 直接分解
for(LL i = 2; i <= sqrt(n); i++)
{
a = 0;
LL cnt = 0;
if(n%i == 0)
{
primes.push_back(i);
while(n%i == 0)
{
e[cnt] += 1;
n /= i;
}
cnt++;
}
}
11582 - Colossal Fibonacci Numbers!
題目鏈接:11582 - Colossal Fibonacci Numbers!
- 題目大意:輸 入兩個非負整數a、b和正整數n(0<=a,b<=,1<=n<=1000),讓你計算f()對n取模的值,其中f(0) = 0,f(1) = 1;且對任意非負整數i,f(i+2)= f(i+1)+f(i)。
- 思路:這道題目既考察了快速冪乘又考察了斐波那契和模的用法。首先需要因爲斐波那契數列值對n取值,可知其序列一定存在一個循環。(因爲f(i+2)= f(i+1)+f(i),當(f[i+1],f[i])二元組重複了就開始了循環,且斐波那契數列取值爲0—n-1範圍內的n個數,所以二元組也有nn個組合,所以nn個值之內必將循環)。
那麼就先算出循環的長度len,len作爲中快速冪乘的模,最終計算出f數組的下標,根據下標就可以求出對應的值了。
數據類型需要使用unsigned long long
, 使用scanf("%lld")輸入時測試樣例可以過就是wro,使用cin就過了。後來查到網上說unsigned long long對應的是llu
。
代碼:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
typedef unsigned long long LL;
const int MAX = 1005;
LL a, b, len, fib[MAX*MAX];
int T, n;
void Fib(int n)
{
len = 1;
fib[0] = 0, fib[1] = 1%n;
for(int i=2; i<=n*n+100; i++)
{
fib[i] = (fib[i-1]+fib[i-2])%n;
if(fib[i]==fib[1] && fib[i-1]==fib[0])
{
len = i-1;
break;
}
}
}
//兩種快速冪,第一種更快更好寫
LL Power(LL a, LL b, LL mod)
{
LL res = 1;
while(b)
{
if(b&1) res = (res*a)%mod;
a = (a*a)%mod;
b >>= 1;
}
return res;
}
LL Power2(LL a, LL p, LL n) {
if(p == 0) return 1;
LL ans = Power2(a, p/2, n);
ans = ans * ans % n;
if(p%2 == 1) ans = ans * a % n;
return ans;
}
int main()
{
#ifdef ONLINE_JUDGE
#else
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
#endif
scanf("%d", &T);
//cin >> T;
while(T--)
{
//cin >> a >> b >> n;
scanf("%llu%llu%d", &a, &b, &n);
Fib(n);
LL idx = Power(a%len, b, len);
printf("%d\n", fib[idx]);
}
return 0;
}
12169 - Disgruntled Judge
題目鏈接:
參考博文:12169 - Disgruntled Judge
- 題目大意:根據的計算公式,輸入T和,然後輸出對應的。
- 思路: 根據x1、x3、a我們可以得出這樣的公式: 。使用擴展歐幾里得算法,我們可以求出b,但是這個過程中a*b有可能會溢出,這題就一定會溢出,所以要用long long,最後得出的b還要乘上c/d 。然後我們就可以使用這個公式計算值和判斷值的正確性。
代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL T,x1[109],x2[109];
void gcd(LL a,LL b,LL& d,LL& x,LL& y) {
if(!b) { d=a; x=1; y=0; }
else { gcd(b,a%b,d,y,x); y-=x*(a/b); }
}
void solve() {
for(int a=10000;a>=0;--a){
LL d,b,k,c=x1[2]-a*a*x1[1];
gcd(a+1,10001,d,b,k);
if(c%d) continue;
else {
b=b*c/d;
int kase=1;
bool ok=true;
while(1) {
x2[kase]=(a*x1[kase]+b)%10001;//計算
kase++;
if(kase==T+1) break;
if(x1[kase]==((a*x2[kase-1]+b)%10001)) continue;//判斷
else { ok=false; break; }
}
if(ok) return;
}
}
}
int main() {
scanf("%lld",&T);
for(int i=1;i<=T;i++)
scanf("%lld",&x1[i]);
solve();
for(int i=1;i<=T;i++)
printf("%lld\n",x2[i]);
return 0;
}
10791 - Minimum Sum LCM
- 題目大意:輸入n,求至少兩個整數,使得他們的最小公倍數爲n,且這些整數的和最小。輸出最小的和。
- 思路:唯一分解定理。設唯一分解式其中是素數,不難發現每個作爲一個單獨的整數時最優。
代碼:
#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
LL n;
int kase = 0;
while(scanf("%lld", &n) && n != 0)
{
LL a, flag = 0, ans = 0;
LL x = (long long)sqrt(n) + 10;
for(LL i = 2; i <= sqrt(n); i++)
{
a = 0;
LL temp = 0;
if(n %i == 0)//表明該素數可被整除
{
flag++;
temp = 1;
while(n%i == 0)
{
temp *= i;
n /= i;
}
}
ans += temp;
}
if(flag == 0)//表明該數是素數或1
ans = n+1;
else if(flag == 1 || n != 1)//只有一個因數或n不等於1
ans += n;
printf("Case %d: %lld\n",++kase, ans);
}
return 0;
}