7.13 模拟赛
数学专题 gyx
A 造题
爆
没看出来gcd还搞错了式子,可以原地退役了
再辗转相减法的基础上,加上统计计算次数即可
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const ll INF=0x3f3f3f3f,N=1000010,Mod=1e9+7;
inline ll read(){
ll x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
ll gcd(ll a,ll b){
return (!b)?a:gcd(b,a%b);
}
ll solve(ll a,ll b){
if(!b) return 0;
return solve(b,a%b)+(a/b);
}
ll n,m,t,cnt=0;
int main(){
n=read(),m=read(),t=read();
if(m==0||n==0) printf("-1
"),exit(0);
if(m>n) swap(m,n);
ll d=gcd(n,m);
n/=d;
m/=d;
printf("%lld
",solve(n,m)*t);
return 0;
}
B 数列
题意:给出一个长度为 (n) 的序列 (a),现求构造出一个长度为 (n) 的序列使每个数不超过给出序列该位置的数且整个序列和 (k) 的最大公约数为 (k) 的方案数
对于每个 (k) 我们处理出它所有的因数并排序,对于序列 (a) 中的每个数,我们在 (k) 的因子中二分查找该数最多能覆盖多少数,即该位置能填多少数,最后乘起来就行了
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const ll INF=0x3f3f3f3f,N=100010,Mod=1e9+7;
inline ll read(){
ll x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
int n,q;
ll a[N],k;
ll p[N],cnt=0,ans=0;
int main(){
n=read(),q=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=q;i++){
k=read();
cnt=0,ans=1;
for(int j=1;j<=sqrt(k);j++){
if(k%j==0) p[++cnt]=j;
if(k%j==0&&j*j!=k) p[++cnt]=k/j;
}
sort(p+1,p+1+cnt);
for(int j=1;j<=n;j++){
(ans*=(upper_bound(p+1,p+1+cnt,a[j])-p-1))%=Mod;
}
printf("%lld
",ans%Mod);
}
return 0;
}
C 矩阵
题意:给出一个数 (n) ,在 (n imes n) 的矩阵中,随机布满 (1sim n^2) 的数字,每个数字只出现一次,定义一种情况的权值为满足一列中最小的数字在 ([1,n]) 之间的列的个数,求权值的期望
每种情况([1,n])之间的数交换位置对答案无影响,([n+1,n^2])之间的数交换位置对答案也无影响所以在最后统计答案的时候要乘上 (n!*(n^2-n)!)
然后考虑 ([1,n]) 之间数的贡献,对于一个数 (i) ,当其放的列中其他数字都比它大时才会贡献权值, (n^2) 个数中比 (i) 大的数共有 (n^2-i) 个,所以在这些数里面挑出来 (n-1) 个就行了,数字 (i) 在该行有 (n) 种选择,最终答案是
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const ll INF=0x3f3f3f3f,N=10000010,Mod=1e9+7;
inline ll read(){
ll x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
ll n,ans=0;
ll can[N],inv[N];
ll fpow(ll a,ll b,ll p){
ll res=1;
for(;b;b>>=1,a=a*a%Mod) if(b&1) res=res*a%Mod;
return res;
}
void init(ll x){
can[0]=1,inv[0]=1;
for(int i=1;i<=x;i++) can[i]=can[i-1]*i%Mod;
inv[x]=fpow(can[x],Mod-2,Mod);
for(int i=x-1;i>=1;i--) inv[i]=inv[i+1]*(i+1)%Mod;
}
int main(){
n=read();
init(n*n);
ll ans=0;
for(int i=1,op;i<=n;i++){
op=n*n*can[n*n-i]%Mod*inv[n*n-n-i+1]%Mod*can[n*n-n]%Mod;
ans=(ans+op)%Mod;
}
printf("%lld
",ans*inv[n*n]%Mod);
return 0;
}
D 欧拉
欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉欧拉
题意:设 (k=sum_{i=1}^n varphi(i*a) mod 10^9+7) ,其中 (a) 保证不能被任何大于 (1) 的完全平方数整除,求 (ans=k^{k^{k^{...^{k}}}}mod p)
先用线性筛筛出来欧拉函数
- 求k
*注:(varphi (k imes n imes p)=p imes varphi(k imes n)) 可以用欧拉函数的素因子表达式证出
递推式出来了!
如果设 (f[n,a]=sum_{i=1}^n varphi(i*a)) ,那么 (f[n,a]=varphi(p) imes f[n,a/p]+f[n/p,a])
- 求无穷幂
上帝与集合的正确用法,做稍稍改动即可
码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cmath>
#include<vector>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<bitset>
#include<cstring>
#define ll long long
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int INF=0x3f3f3f3f,N=10000010,Mod=1e9+7;
inline ll read(){
ll x=0,y=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') y=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*y;
}
ll n,a,p;
ll k=0,sum[N];
bool notp[N];
ll cnt=0,phi[N],pri[N],mindiv[N];
void getphi(ll n){
cnt=0;
notp[1]=1,phi[1]=1;
for(int i=2;i<=n;i++){
if(!notp[i]) pri[++cnt]=mindiv[i]=i,phi[i]=i-1;
for(int j=1;j<=cnt&&pri[j]*i<=n;j++){
notp[pri[j]*i]=1;
if(i%pri[j]==0){phi[pri[j]*i]=phi[i]*pri[j];break;}
else phi[pri[j]*i]=phi[i]*(pri[j]-1);
mindiv[i*pri[j]]=pri[j];
}
}
sum[0]=0;
for(int i=1;i<=N-10;i++) sum[i]=(sum[i-1]+phi[i])%Mod;
}
ll fpow(ll a,ll b,ll o){
int ret=1;
for(;b;b>>=1,a=a*a%o) if(b&1) ret=ret*a%o;
return ret;
}
ll solve(ll op,ll p){
if(p==1) return 0;
return fpow(op,(solve(op,phi[p])%Mod+phi[p])%Mod,p);
}
int getk(int n,int m){
if(n==1) return sum[m]%Mod;
if(m==1) return phi[n];
if(m==0) return 0;
int p=mindiv[n];
return (phi[p]*getk(n/p,m)%Mod+getk(n,m/p))%Mod;
}
signed main(){
getphi(N-10);
n=read(),a=read(),p=read();
k=getk(a,n);
printf("%lld
",solve(k,p));
return 0;
}