数论练习
数论#
P1891 疯狂 LCM#
题意:
给定 ,求:
思路:
先把 换成 :
加一个枚举因数的
即
用 替换原本的
由于 成对出现,可以用 替换
可以发现这个式子与 有一定联系,因为
多了一个
一个小定理:若 则
因此原式可以两对两对的统计,可以写成
这样就可以计算了
注意 的时候特判
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
const int N=1e6+5;
#define ll long long
int cnt;
int p[N],phi[N];
bool not_p[N];
ll f[N];
inline void get_phi(){
phi[1]=1;
not_p[1]=1;
for(int i=2;i<N;++i){
if(!not_p[i]){
p[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*p[j]<N;++j){
not_p[i*p[j]]=1;
if(i%p[j]==0){
phi[i*p[j]]=phi[i]*p[j];
break;
}
else
phi[i*p[j]]=phi[i]*(p[j]-1);
}
}
for(int i=1;i<N;++i)
for(int j=1;j*i<N;++j)
f[i*j]+=(i==1?1:1ll*phi[i]*i/2);
}
inline ll solve(int x){
return f[x]*x;
}
signed main(){
int T=read();
get_phi();
while(T--)
cout<<solve(read())<<endl;
}
P1128 求正整数#
题意:
对于任意输入的正整数 ,请求出具有 个不同因子的最小正整数 。
思路:
由于 ,所以只用考虑前 个质数作为质因子
考虑
由于数据太大,将每个数取 再
表示搜到的正整数为 , 为 的因数个数, 表示搜到了 个质数,然后乱搜
最后再加上一个高精乘单精即可
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,ans[100005],res[20],pos[20];
int p[20]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53};
double mn=1e9,v[20];
inline void dfs(double x,int y,int z){
if(x>=mn||z>16) return;
if(y==1){
mn=x;
memset(res,0,sizeof(res));
for(int i=1;i<=z-1;i++)
res[i]=pos[i];
return ;
}
for(int i=0;(i+1)*(i+1)<=y;++i)
if(y%(i+1)==0){
if(i){
pos[z]=i;
dfs(x+v[z]*i,y/(i+1),z+1);
}
if((i+1)*(i+1)!=y){
pos[z]=y/(i+1)-1;
dfs(x+v[z]*(y/(i+1)-1),i+1,z+1);
}
}
}
signed main(){
n=read();
for(int i=1;i<=16;++i)
v[i]=log(p[i]);
dfs(0,n,1);
int top=1;
ans[1]=1;
for(int i=1;i<=16;++i){
for(;res[i];--res[i]){
for(int j=1;j<=top;++j) ans[j]*=p[i];
for(int j=1;j<=top;++j) ans[j+1]+=ans[j]/10,ans[j]%=10;
if(ans[top+1]) ++top;
while(ans[top]/10)
ans[top+1]+=ans[top]/10,ans[top]%=10,++top;
}
}
for(int i=top;i;--i) cout<<ans[i];
}
P2606 排列计数#
题意:
称一个 的排列 是 Magic
的,当且仅当
计算 的排列中有多少是 Magic
的,对 取模
思路:
这道题就是在问: 这 个数构成一棵完全二叉树,求出满足小根堆性质的树总共多少种
考虑 , 表示当前节点为 的总方案数,节点 的子树大小为
则有:
由于要取模,搞个
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
#define int long long
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,p;
int f[N],sz[N];
int frac[N];
inline int qpow(int x,int idx){
if(!idx) return 1;
int t=qpow(x,idx>>1);
if(idx&1) return t*t%p*x%p;
return t*t%p;
}
inline int C(int x,int y){
if(x<y) return 0;
return (frac[x]*qpow(frac[y],p-2))%p*qpow(frac[x-y],p-2)%p;
}
inline int Lucas(int x,int y){
if(!y) return 1;
return C(x%p,y%p)*Lucas(x/p,y/p)%p;
}
signed main(){
n=read(),p=read();
frac[0]=1;
for(int i=1;i<N;++i) frac[i]=frac[i-1]*i%p;
for(int i=1;i<=n;++i) sz[i]=1;
for(int i=n;i>=2;--i) sz[i>>1]+=sz[i];
for(int i=n+1;i<=n*2+1;++i) f[i]=1;
for(int i=n;i;--i) f[i]=Lucas(sz[i]-1,sz[i<<1])%p*f[i<<1]%p*f[i<<1|1]%p;
cout<<f[1]<<endl;
}
P5323 光线#
题意:
当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收。
设对于任意 ,有 单位的光会穿过它,有 的会被反射回去。
现在 层玻璃叠在一起,有 单位的光打到第 层玻璃上,那么有多少单位的光能穿过所有 层玻璃呢?
思路:
考虑
设 表示每 单位光线穿过第 块玻璃的概率是多少,答案显然是
但是光线会反射,还要考虑反射回上一个再反射回来的光线的贡献
设 表示每 单位光线自下而上经过第 块玻璃然后被向下反射的概率
那么
且
然后就可以递推了
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=5e5+5;
#define int long long
inline int read(){
int x=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int n,ans=1;
int a[N],b[N];
int f[N],g[N];
inline int qpow(int x,int idx){
if(!idx) return 1;
int t=qpow(x,idx>>1);
return idx&1?t*t%mod*x%mod:t*t%mod;
}
signed main(){
n=read();
int tmp=qpow(100,mod-2);
for(int i=1;i<=n;++i) a[i]=read()*tmp%mod,b[i]=read()*tmp%mod;
f[1]=a[1],g[1]=b[1];
for(int i=2;i<=n;++i){
tmp=qpow((1-b[i]*g[i-1]%mod+mod)%mod,mod-2);
f[i]=a[i]*tmp%mod;
g[i]=(b[i]+(a[i]*g[i-1]%mod*f[i]%mod)%mod)%mod;
}
for(int i=1;i<=n;++i) ans=(ans*f[i])%mod;
printf("%lld",ans);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现