数学小练
Goldbach’s Conjecture
线性筛出所有范围内的质数,暴力枚举就行了。
(一开始
c
i
n
cin
cin 挂了,所以直接上了快读,实际上
s
c
a
n
f
scanf
scanf 就行了)
线性筛
▼
\blacktriangledown
▼
void pre(){
int n=N-10;
for(int i=2;i<=n;++i){
if(!v[i]) p[++m]=v[i]=i;
for(int j=1;j<=m;++j){
if(p[j]>v[i] || p[j]>n/i) break;
v[p[j]*i]=p[j];
}
}
}
主程序 ▼ \blacktriangledown ▼
read(n);
while(n){
for(int j=2;p[j]<=n;++j){
if(v[n-p[j]]==n-p[j]){
prt(n),printf(" = "),prt(p[j]),printf(" + "),prt(n-p[j]),puts("");
break;
}
}
read(n);
}
Prime Distance/质数距离
2 31 2^{31} 231 的范围显然不能线性筛出所有质数,但我们可以根据线性筛的思想,求出范围内的所有数的最小质因子,复杂度 O ( R ) O(\sqrt R) O(R) ,又加上 L − R L-R L−R的值很小 ,对于筛出来的每一个质数 p p p,把 [ L , R ] [L,R] [L,R] 中能被 p p p 整除的数标记为合数。剩下没被标记的数既是质数,时间复杂度 O ( R l o g l o g R + ( R − L ) l o g l o g R ) O(\sqrt Rloglog\sqrt R+(R-L)loglogR) O(RloglogR+(R−L)loglogR) 。
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100006, L = 1000006, M = 46340, INF = 0x7fffffff;
bool v[L];
vector<int> p, ans;
int main() {
memset(v, 1, sizeof(v));
for (int i = 2; i <= N; i++)
if (v[i]) {
p.push_back(i);
for (int j = 2; j <= N / i; j++) v[i*j] = 0;
}
unsigned int l, r;
while (cin >> l >> r) {
memset(v, 1, sizeof(v));
ans.clear();
if (l == 1) v[0] = 0;
for (unsigned int i = 0; i < p.size(); i++)
for (unsigned int j = (l - 1) / p[i] + 1; j <= r / p[i]; j++)
if (j > 1) v[p[i]*j-l] = 0;
for (unsigned int i = l; i <= r; i++)
if (v[i-l]) ans.push_back(i);
int minn = INF, maxx = 0, x1, y1, x2, y2;
for (unsigned int i = 0; i + 1 < ans.size(); i++) {
int num = ans[i+1] - ans[i];
if (num < minn) {
minn = num;
x1 = ans[i];
y1 = ans[i+1];
}
if (num > maxx) {
maxx = num;
x2 = ans[i];
y2 = ans[i+1];
}
}
if (!maxx) puts("There are no adjacent primes.");
else printf("%d,%d are closest, %d,%d are most distant.\n", x1, y1, x2, y2);
}
return 0;
}
反素数 Antiprime
樱花
先转化一下式子,通分
x
+
y
x
y
=
1
n
!
\frac{x+y}{xy}=\frac{1}{n!}
xyx+y=n!1变形
x
y
−
n
!
(
x
+
y
)
=
0
xy-n!(x+y)=0
xy−n!(x+y)=0左右同时加上
(
n
!
)
2
(n!)^2
(n!)2
(
n
!
)
2
−
n
!
(
x
+
y
)
+
x
y
=
(
n
!
)
2
(n!)^2-n!(x+y)+xy=(n!)^2
(n!)2−n!(x+y)+xy=(n!)2 因式分解
(
x
−
n
!
)
(
y
−
n
!
)
=
(
n
!
)
2
(x-n!)(y-n!)=(n!)^2
(x−n!)(y−n!)=(n!)2设
a
=
x
−
n
!
,
b
=
y
−
n
!
a=x-n! , b=y−n!
a=x−n!,b=y−n! 则
a
b
=
(
n
!
)
2
ab=(n!)^2
ab=(n!)2
设
n
!
=
p
1
c
1
×
p
2
c
2
×
⋯
×
p
k
c
k
n!=p_{1}^{c_1}\times p_{2}^{c_2}\times\cdots\times p_{k}^{c_k}
n!=p1c1×p2c2×⋯×pkck 则
(
n
!
)
2
=
p
1
2
c
1
×
p
2
2
c
2
×
⋯
×
p
k
2
c
k
(n!)^2=p_{1}^{2c_1}\times p_{2}^{2c_2}\times\cdots\times p_{k}^{2c_k}
(n!)2=p12c1×p22c2×⋯×pk2ck
所以只要计算 ( n ! ) 2 (n!)^2 (n!)2 的约数个数,即 ( 2 c 1 + 1 ) ( 2 c 2 + 1 ) ⋯ ( 2 c k + 1 ) (2c_1+1)(2c_2+1)\cdots(2c_k+1) (2c1+1)(2c2+1)⋯(2ck+1)。关于 c i c_i ci 求法详见阶乘分解,这里给公式 c i = ∑ p k ≤ N ⌊ N p k ⌋ c_i=\sum_{p^{k}\leq{N}}\lfloor\frac{N}{p^{k}} \rfloor ci=pk≤N∑⌊pkN⌋
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
T ch=getchar(),xx=1;x=0;
while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x*=xx;
}
template<typename T>inline void prt(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) prt(x/10);
putchar(x%10|48);
}
#define int long long
#define N 1000010
const int MOD=1e9+7;
int v[N],p[N],m,ans;
void pre(int n){
for(int i=2;i<=n;++i){
if(!v[i]) p[++m]=i,v[i]=i;
for(int j=1;j<=m;++j){
if(p[j]>v[i] || p[j]>n/i) break;
v[i*p[j]]=p[j];
}
}
}
signed main(){
int n;
read(n);
pre(n);
ans++;
for(int i=1;i<=m;++i){
int k=0,g=p[i];
while(n>=g){
k+=n/g;
g*=p[i];
}
ans=(ans*(2*k+1))%MOD;
}
prt(ans);
return 0;
}
方程的解
题目等价为将 x x x 个球放入 k k k 个篮子中 ,篮子非空,假设 x x x 个球有 x − 1 x-1 x−1 个缝,要放入 k − 1 k-1 k−1 个板子, 所以答案为 C n − 1 k − 1 \mathrm{C}_{n-1}^{k-1} Cn−1k−1 ,记得高精
#include<bits/stdc++.h>
using namespace std;
#define N 5000
const int mm=10;
struct A {
int a[N],len;
A(int x=0):a() {
for (int i=x; i; i/=mm) a[++len]=i%mm;
if (!len) len++;
}
void print() {
for (int i=len; i>=1; i--) printf("%d",a[i]);
printf("\n");
}
};
A operator * (const A &a,const A &b) {
A c;
c.len=a.len+b.len;
for (int i=1; i<=a.len; i++)
for (int j=1; j<=b.len; j++) {
c.a[i+j-1]+=a.a[i]*b.a[j];
c.a[i+j]+=c.a[i+j-1]/mm;
c.a[i+j-1]%=mm;
}
while (c.len>1&&!c.a[c.len]) c.len--;
return c;
}
A operator / (const A &a,int k) {
A c;
c.len=a.len;
int x=0;
for (int i=a.len; i>=1; i--) {
x=x*mm+a.a[i];
c.a[i]=x/k;
x%=k;
}
while (c.len>1&&!c.a[c.len]) c.len--;
return c;
}
bool operator < (const A &a,const A &b) {
if (a.len!=b.len) return a.len<b.len;
for (int i=a.len; i>=1; i--)if (a.a[i]!=b.a[i]) return a.a[i]<b.a[i];
return 0;
}
bool operator > (const A &a,const A &b) {
return b<a;
}
int x,k;
int qpow(int x,int y,int p) {
int ret=1;
while(y) {
if(y&1) ret=ret*x%p;
x=x*x%p;
y>>=1;
}
return ret;
}
int main() {
scanf("%d%d",&k,&x);
x=qpow(x%1000,x,1000);
if(k>x || x==0) puts("0");
else if(k==1 || k==x) puts("1");
else {
x--,k--;
A ans;
ans.a[1]=1;
ans.len=1;
for(int i=x-k+1;i<=x;++i){
A s;
int j=i;
s.len=0;
while(j){
s.a[++s.len]=j%10;
j/=10;
}
ans=ans*s;
}
for(int i=1;i<=k;++i) ans=ans/i;
ans.print();
五指山
解同余方程 k d ≡ y − x ( m o d n ) kd \equiv {y-x} \pmod{n} kd≡y−x(modn)
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
T ch=getchar(),xx=1;x=0;
while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x*=xx;
}
template<typename T>inline void prt(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) prt(x/10);
putchar(x%10|48);
}
#define ll long long
void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){x=1;y=0;return ;}
exgcd(b,a%b,x,y);
int z=x;x=y;y=z-y*(a/b);
return ;
}
ll gcd(ll a,ll b){
return b==0 ? a : gcd(b,a%b);
}
ll T,n,d,a,b,x,y;
int main(){
read(T);
while(T--){
read(n),read(d),read(a),read(b);
b-=a;
int k=gcd(d,n);
int t=n/k;
if(b%k){
puts("Impossible");
}
else {
exgcd(d,n,x,y);
x*=(b/k);
x=(x%t+t)%t;
prt(x);
puts("");
}
}
}
Xiao 9*大战朱最学
详见曹冲养猪
Matrix Power Series
先抛开矩阵不谈,题目即为如何在不用求和公式(不用除法)求等比数列前
k
k
k 项和。
假设
k
k
k 为
16
16
16 ,
S
16
=
a
1
+
a
2
+
⋯
+
a
16
=
(
a
1
+
⋯
+
a
8
)
+
(
a
9
+
⋯
+
a
16
)
=
(
a
1
+
⋯
+
a
8
)
×
a
8
S_{16}=a^{1}+a^2 +\cdots +a^{16}=(a^1+\cdots+a^8)+(a^9+\cdots+a^{16})=(a^1+\cdots+a^8)\times a^8
S16=a1+a2+⋯+a16=(a1+⋯+a8)+(a9+⋯+a16)=(a1+⋯+a8)×a8,这样只要求
S
8
S_{8}
S8 和
a
8
a^8
a8 同理
S
8
S_{8}
S8 也可以这样得出这样就可以 递归 + 快速幂 在
O
(
l
o
g
N
)
O(logN)
O(logN) 的效率得出来,最后套上矩阵,在递归的时候注意
k
k
k 的奇偶性就行了。
#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x){
T ch=getchar(),xx=1;x=0;
while(!isdigit(ch)) xx=ch=='-'?-1:xx,ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
x*=xx;
}
template<typename T>inline void prt(T x){
if(x<0) putchar('-'),x=-x;
if(x>9) prt(x/10);
putchar(x%10|48);
}
const int N=36;
struct M{int a[N][N];};
int n,k,m;
M add(M x,M y) {
M c;
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
c.a[i][j]=(x.a[i][j]+y.a[i][j])%m;
return c;
}
M mul(M x,M y) {
M c;
memset(c.a,0,sizeof(c.a));
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
for (int k = 0; k < n; k++)
c.a[i][j] = (x.a[i][k] * y.a[k][j] % m + c.a[i][j]) % m;
return c;
}
M ksm(M x,int k){
M c;
memset(c.a,0,sizeof(c.a));
for(int i=0;i<n;++i) c.a[i][i]=1;
while(k){
if (k&1) c=mul(c,x);
x=mul(x,x);
k>>=1;
}
return c;
}
M get(M x,int k) {
if(k==1) return x;
M y=ksm(x,(k+1)>>1);
M z=get(x,k>>1);
return k&1 ? add(x,mul(add(x,y),z)):mul(add(ksm(x,0),y),z);
}
int main() {
M x;
read(n),read(k),read(m);
for (int i=0;i<n;i++)
for (int j=0;j<n;j++)
read(x.a[i][j]);
x = get(x,k);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++)
cout << x.a[i][j] << " ";
cout << endl;
}
return 0;
}
石头游戏
详见注释
#include<bits/stdc++.h>
#define LL long long
using namespace std;
int n,m,t,act,p;
char b[10][10],s[11];
int num(int i,int j){return (i-1)*m+j;}
void mul(LL f[65],LL a[65][65]){
LL c[65];
memset(c,0,sizeof(c));
for(int i=0;i<p;i++)
for(int j=0;j<p;j++)
c[i]=c[i]+f[j]*a[j][i];
memcpy(f,c,sizeof(c));
}
void selfmul(LL a[65][65],LL b[65][65]){
LL c[65][65];
memset(c,0,sizeof(c));
for(int i=0;i<p;i++)
for(int k=0;k<p;k++)
if(a[i][k])
for(int j=0;j<p;j++)
c[i][j]=c[i][j]+a[i][k]*b[k][j];
memcpy(a,c,sizeof(c));
}
int a[10][10];//每个点的操作序号
int c[10][10];//每个点对应操作的具体步骤
LL f[65],d[65][65],state[65][65][65],ans;
int main(){
scanf("%d%d%d%d",&n,&m,&t,&act);
for(int i=1;i<=n;i++){
scanf("%s",s);
for(int j=1;j<=m;j++) a[i][j]=(s[j-1]^48)+1;//每个点的操作序号
}
for(int i=1;i<=act;i++) scanf("%s",b[i]);
p=n*m+1;
for(int k=1;k<=60;k++){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int x=a[i][j],y=c[i][j];
if(isdigit(b[x][y])){
state[k][0][num(i,j)]=b[x][y]-'0';/*添加*/
state[k][num(i,j)][num(i,j)]=1;/*继承*/}
if(b[x][y]=='N' && i>1) state[k][num(i,j)][num(i-1,j)]=1;
if(b[x][y]=='W' && j>1) state[k][num(i,j)][num(i,j-1)]=1;
if(b[x][y]=='S' && i<n) state[k][num(i,j)][num(i+1,j)]=1;
if(b[x][y]=='E' && j<m) state[k][num(i,j)][num(i,j+1)]=1;
c[i][j]=(y+1)%strlen(b[x]);//操作循环
}
state[k][0][0]=1;
}
memcpy(d,state[1],sizeof(state[1]));//d为A的60次方
for(int k=2;k<=60;k++) selfmul(d,state[k]);
f[0]=1;
int w=t/60;
while(w){//矩阵快速幂 d的w次方
if(w&1) mul(f,d);
selfmul(d,d);
w>>=1;
}
w=t%60;
for(int i=1;i<=w;i++) mul(f,state[i]);
for(int i=1;i<p;i++) ans=max(ans,f[i]);
printf("%lld",ans);
return 0;
}