實現程式碼:
int exgcd(int a,int b, int &x, int &y){
if(b == 0){
x = 1;
y = 0;
return a;
}
int d = exgcd(b, a % b, x, y);
int k = x;
x = y;
y = k - (a / b) * y;
return d;
}
int main(){
int a = read(), b = read();
int x, y;
int d = exgcd(a, b, x, y);
cout << d << " " << x << " " << y << '\n';
return 0;
}
#define ll long long
ll fac[N], ifac[N];
const ll p=998244353;
ll power(ll a, ll b){
ll ret = 1;
while (b){
if(b & 1){
ret = ret * a % p;
}
a = a * a % p;
b >>= 1;
}
return ret;
}
ll c(int a, int b){
if(a < b || b < 0){
return 0;
}
return fac[a] * ifac[b] % p * ifac[a - b]% p;
}
void initialize(){
fac[0]= 1;
for(int i=1; i < N; i++){
fac[i] = fac[i - 1] * i % p;
}
ifac[N - 1] = power(fac[N - 1], p - 2);
for(int i = N - 2;i >= 0;i--){
ifac[i]= ifac[i + 1] * (i + 1) % p;
}
}
小凱的數字
思路:
我們知道 \(𝑥≡𝑥\)的"數位和" \((\mod 9)\) 。
所以 \(\overline{𝑙(𝑙+1)(𝑙+2)\cdots r}\)\(≡𝑙\)的"數位和"\(+(𝑙+1)\)的"數位和"\(+⋯+𝑟\)的"數位和"\(≡𝑙+(𝑙+1)+…+𝑟 (\mod 9)\)。
問題變為計算 \(\frac{(𝑙+𝑟)(𝑟−𝑙+1)}{2}\)。\(/2\) 可以變為 \(×5\) 。
std:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<unordered_map>
#include<bitset>
#define int long long
using namespace std;
const int MAXN=100005;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
signed main(){
int q;
long long ans;
q=read();
while(q--){
int l,r;
l=read();
r=read();
ans=(l+r)%9*(r-l+1)%9*5%9;
cout<<ans<<'\n';
}
return 0;
}
中國剩餘定理
給定一些 \(x≡a_𝑖 \pmod {m_i}\) 的限制,求 \(x\)。保證 \(m_i\) 兩兩互質。
我們只需要每次合併兩個方程。
現在考慮
即
代入得
。使用擴充套件歐幾里得演算法計算出 \(k_1,k_2\)(由於 \(\gcd(m_1,m_2 )=1\),則一定有解),然後代回得到 \(x\) 的一個特解 \(x_0\) 。
將兩個方程合併為一個新的方程 \(x≡x_0 \pmod {m_1 m_2}\)。
實際上 \(k_1=(a_2−a_1 ) m_1^(−1)\),其中 \(m_1^(−1)\) 表示 \(m_1\) 在 \(\mod m_2\) 下的逆元。
小凱的疑惑
思路:
若 \(𝑀\) 無法被支付,則 \(𝑎𝑥+𝑏𝑦=𝑀\) 沒有自然數解。
假設 \(𝑎𝑥_0+𝑏𝑦_0=𝑀\) 是一組特解,如果$ 𝑥_0,𝑦_0$ 其中有負數(不妨設 \(𝑦_0<0\)),就需要讓 \(𝑥_0\) 幫他勻一點,勻到 \(≥0\) 為止。
具體地,設$ 𝑥_0=𝑘𝑏+𝑟$ (\(0≤𝑟<𝑏\)) ,那麼$ 𝑎𝑟+𝑏(𝑦_0+𝑘𝑎)=𝑀$ 是最極限的情況。因為 \(𝑥_0\) 這一邊也需要 ≥0 。
如果此時$ 𝑦_0+𝑘𝑎$ 仍然 \(<0\) ,就說明無解。可知 \(𝑦_0+𝑘𝑎=−1,𝑟=𝑏−1\) 時 \(𝑀\) 最大為 $𝑎(𝑏−1)−𝑏=𝑎𝑏−𝑎−𝑏 $
質數篩
素數判斷的方法
- 既然第一種方法時間複雜度太大,那麼我們要考慮一種新的方式。首先給出這種方法的名字——埃式篩。聽上去是不是一個很高大上的名字,但其實原理很簡單,我們用一個陣列來存放n以內的所有質數,我們要用到一個布林陣列來標記n以內的所有不是質數的數(也要標記1,1既不是質數也不是合數)。再標記此質數所有的倍數(因為質數所有的倍數都不是質數)。最後輸出所有質數
程式碼:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
bool is[10005];
int prim[10005];
int cnt=0;
void Aprime(int n){
is[1]=1;//1既不是質數也不是合數
for(int i=2;i<=n;i++){//遍歷2~n之間的所有整數
if(is[i]==0){//如果沒有被標記過,說明是質數
prim[++cnt]=i;//儲存質數
for(int j=i*2;j<=n;j+=i){//標記所有此質數的倍數
is[j]=1;
}
}
}
}
int main(){
int n;
cin>>n;
Aprime(n);//呼叫函式
for(int i=1;i<=cnt;i++){
cout<<prim[i]<<"\n";//輸出質數
}
return 0;
}
素數判斷的方法2:
埃式篩的缺點在於有和數被重複標記了多次,所以還不是最優解,這裡奉上更快的辦法——尤拉篩。尤拉篩,也叫線性篩,是更快的判斷質數的方法。其思路在埃式篩的基礎上有所改進,讓質數庫裡的每個質數分別與迴圈中的i相乘,如果i取餘這個質數等於0,則直接跳出迴圈,避免重複標記,節省時間。
程式碼:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
bool is[10005];
int prim[10005];
int cnt=0;
void Aprime(int n){
is[1]=1;//1既不是質數也不是合數
for(int i=2;i<=n;i++){
if(is[i]==0){//如果沒有被標記過,說明是質數
prim[++cnt]=i;//儲存質數
}
for(int j=1;j<=cnt&&i*prim[j]<=n;j++){//質數不超過n
is[i*prim[j]]=1;//用新數去乘每一個質數
if(i%prim[j]==0){
break;//不重複標記,取餘等於0就跳出迴圈
}
}
}
}
int main(){
int n;
cin>>n;
Aprime(n);//呼叫函式
for(int i=1;i<=cnt;i++){
cout<<prim[i]<<"\n";//輸出質數
}
return 0;
}
選數
思路:
由於本題資料較水,對每個子集和暴力試除就能過。
但如果資料不水,需要使用線性篩,並且要壓一下空間。
std:
#include<bits/stdc++.h>
using namespace std;
bool isprime(int a){
for(int i=2;i*i<=a;i++)if(a%i==0)return 0;
return 1;
}
long long ans,a[25],n,k;
void dfs(int m, int sum, int s){
if(m == k){
if(isprime(sum))ans++;
return ;
}
for(int i = s; i<n;i++)dfs(m+1,sum+a[i],i+1);
return ;
}
int main(){
scanf("%d%d",&n,&k);
for(int i = 0; i < n; i++)scanf("%d",&a[i]);
dfs(0, 0, 0);
printf("%d\n",ans);
return 0;
}
選素數
思路:
假設一開始是 𝑥 ,操作一次變為 𝑚 ,操作兩次變為 𝑛 。
第一次操作選的 \(𝑝_1\) 需要滿足 \(𝑚−𝑝_1<𝑥≤𝑚\)。所以對於一個固定的 \(𝑚\) ,最小的可行 𝑥=\(\min_{p|n}\min_{n-p<m\le n}f(m)\) 。設 \(𝑓(𝑚)=𝑚−𝑝_𝑚𝑎𝑥+1\) 。
第二次操作選的 \(𝑝_2\) 需要滿足 \(𝑛−𝑝_2<𝑚≤𝑛\)。我們需要找一個 \(𝑓\) 最小的 \(𝑚\),即答案為\(\min_{p|n}\min_{n-p<m\le n}f(m)\)。
程式碼
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<unordered_map>
#include <climits>
#define ll long long
using namespace std;
const int MAXN = 1000010;
const int N = 1000000;
int n;
bool b[MAXN];
int prime[MAXN], idx;
int f[MAXN];
int ans = INT_MAX;
inline int get(int x){
if (!b[x]) return INT_MAX;
return x - f[x] + 1;
}
int main(){
scanf("%d", &n);
for (int i = 2; i <= N; ++i){
if (!b[i]) prime[++idx] = f[i] = i;
for (int j = 1; j <= idx && (ll) i * prime[j] <= N; ++j){
b[i * prime[j]] = true;
f[i * prime[j]] = max(f[i], prime[j]);
if (i % prime[j] == 0) break;
}
}
for (int i = get(n); i <= n; ++i)
ans = min(ans, get(i));
if (ans == INT_MAX) puts("-1");
else printf("%d\n", ans);
return 0;
}
數列之異或
思路:
\(2𝑘⊕(2𝑘+1)=1\)
所以 \(𝑁\) 為奇數時
\(1⊕2⊕3⊕⋯⊕𝑁=1⊕(2⊕3)⊕⋯⊕(𝑁−1⊕𝑁)=1⊕1⊕⋯⊕1\)\(=\begin{cases} 0, & \frac{N-1}{2}為奇數\\ 1, & \frac{N-1}{2}為偶數\\ \end{cases}\)
\(𝑁\) 為偶數時,令計算 \(𝑁−1\) 的答案,再異或上 \(𝑁\)
程式碼
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<unordered_map>
#include<bitset>
#define int long long
using namespace std;
const int MAXN=100005;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-48;
ch=getchar();
}
return x*f;
}
signed main(){
int n;
n=read();
if(n%2!=0){
if(((n-1)/2)%2!=0){
cout<<0;
}else{
cout<<1;
}
}else{
if(((n-1)/2)%2!=0){
cout<<(0^n);
}else{
cout<<(1^n);
}
}
return 0;
}