『数学』做题记录
P8380
出在模拟赛里面了,推的式子不能浪费,所以提供两种解法。
玩一下什么情况 \(y^x=x^z\) 就是考虑将 \(x\) 表示为 \(m^a\) 的形式,\(y\) 表示为 \(m^b\) 的形式,然后需要满足的是 \(m^{bx}=m^{az}\),而由于我们是在计数,考虑构造一种双射的形式:对于一个三元组 \((m,a,b)\) 能唯一对应一个 \((x,y)\),对于一组合法的 \((x,y)\) 一定能射到一组 \((m,a,b)\) 上。
不妨通过应定 \(\gcd(a,b)=1\) 来保证这一点,考虑一组 \((x,y)\) 能表示成 \((m,a,b)\) 而 \(\gcd(a,b)\not=1\),不难通过变化为 \((m^{\gcd(a,b)},\dfrac{a}{\gcd(a,b)},\dfrac{a}{\gcd(a,b)})\) 来保证计数不重。
那么可以很轻松地写出式子:
特判一下 \(m=1\) 的情况:
由于 \(\gcd(a,b)=1\):
实际上,推到这步这题就结束了,但是这题是个大粪卡常题。
你但凡观察一下,你直接枚举 \(a,b\) 然后算出 \(m\) 的上界 \(t\),然后算个 \(\sum\limits_{m=2}^{t} [a|m^a]\) 就没了。
然后想了一下,你可能想在 \(t\) 比较小的时候预处理这部分。
而不难发现,当 \(a\geq 3\),有 \(t\leq 10^6\)。
然后对于 \(a=1\) 这个 \(a|m^a\) 没有限制,而 \(a=2\),\(a|m^2\) 其实就是 \(2|m\)。
好,这个做法通过 pow 调整可以做到 \(O(n\log n+T \log^2 n)\),或者通过二分做到 \(O(n\log n+T \log^2 n \log \log n)\)。
有预处理的做法没意思,我们搞点有意思的,这部分大致是我赛时的思路(虽然赛时没有预处理而是后面这部分暴力做了)。
考虑一下你在写暴力判断 \(a|m^a\) 怎么判断的,初始一个 \(q=a\),不断将 \(q \rightarrow \dfrac{q}{\gcd(q,m)}\) 操作 \(a\) 次,若 \(q=1\) 则返回 true。
这个是在做什么?考虑 \(m\) 的所有质因子 \(p^e\),考虑 \(a\) 中含有的同样质因子 \(p^{e^{\prime}}\),上述判断相当于是对于所有 \(p\),判断是否都有 \(ea\geq e^{\prime}\),所以相当于我给每个 \(a\) 中质因子 \(p\) 的指数在 \(m\) 中都有限制。
那么不难算出这个偏序关系中最小的 \(m^{\prime}\),那么对于 \(m\) 是 \(m^{\prime}\) 的倍数就是 \(a|m^a\) 成立的充要条件。
设这个 \(m^{\prime}=f(a)\),那么 \(\sum\limits_{m=2}^{t}[a|m^a]=[f(a)=1](t-1)+[f(a)>1] \lfloor\dfrac{t}{f(a)}\rfloor\)
这个做法的复杂度同样是 \(O(T \log^2 n \log \log n)\)。
Code:
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2")
//#pragma GCC optimize("Ofast","unroll-loops","inline")
#include<bits/stdc++.h>
#define ll long long
#define int ll
#define pb push_back
using namespace std;
const int N=1e6+20,M=1e6+20,mod=1e9+7,LGN=63;
const int mx[]={0,1000000000000000010ll,1000000010,1000010,32000,4000,1010};
const int Mx=2e18;
const int Lim=1e18;
namespace FastIO {
struct IO {
char ibuf[(1 << 20) + 1], *iS, *iT, obuf[(1 << 20) + 1], *oS;
IO() : iS(ibuf), iT(ibuf), oS(obuf) {} ~IO() { fwrite(obuf, 1, oS - obuf, stdout); }
#if ONLINE_JUDGE
#define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
#else
#define gh() getchar()
#endif
inline bool eof (const char &ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == 't' || ch == EOF; }
inline long long read() {
char ch = gh();
long long x = 0;
bool t = 0;
while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
return t ? ~(x - 1) : x;
}
inline void read (char *s) {
char ch = gh(); int l = 0;
while (eof(ch)) ch = gh();
while (!eof(ch)) s[l++] = ch, ch = gh();
}
inline void read (double &x) {
char ch = gh(); bool t = 0;
while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
while (ch >= '0' && ch <= '9') x = x * 10 + (ch ^ 48), ch = gh();
if (ch != '.') return t && (x = -x), void(); ch = gh();
for (double cf = 0.1; '0' <= ch && ch <= '9'; ch = gh(), cf *= 0.1) x += cf * (ch ^ 48);
t && (x = -x);
}
inline void pc (char ch) {
#ifdef ONLINE_JUDGE
if (oS == obuf + (1 << 20) + 1) fwrite(obuf, 1, oS - obuf, stdout), oS = obuf;
*oS++ = ch;
#else
putchar(ch);
#endif
}
template<typename _Tp>
inline void write (_Tp x) {
static char stk[64], *tp = stk;
if (x < 0) x = ~(x - 1), pc('-');
do *tp++ = x % 10, x /= 10;
while (x);
while (tp != stk) pc((*--tp) | 48);
}
inline void write (char *s) {
int n = strlen(s);
for (int i = 0; i < n; i++) pc(s[i]);
}
} io;
inline long long read () { return io.read(); }
template<typename Tp>
inline void read (Tp &x) { io.read(x); }
template<typename _Tp>
inline void write (_Tp x) { io.write(x); }
}
using namespace FastIO;
int fl[LGN][LGN],f[LGN],pw[LGN][N],L[LGN];
int qpow(int a,int b){
if(b==0) return 1;
int res=1;
while(b){if(b&1){if(res>Lim/a) return Lim+1;res=res*a;}b>>=1;if(!b) break;if(a>Lim/a) return Lim+1;a=a*a;}
return res;
}
inline int get(int x,int v){
if(v==1) return x;
if(v==2) return sqrtl(x);
int l=0,r=L[v],ans=0;
while(l<=r){
int mid=(l+r)/2;
if(pw[v][mid]<=x) l=mid+1,ans=mid;
else r=mid-1;
}
return ans;
}
inline int Lg(int x,int B){
int res=0,p=1;
while(p<=B/x) p*=x,res++;
return res;
}
inline int calc(int i,int A,int B,int C){
int p=Lg(2,B),res=0;
int g=f[i];
for(int y=1;y<=p;y++) if(fl[i][y]){
int lim=get(B,y);
lim=min(lim,get((ll)min((__int128)A,((__int128)C*i/y)),i));
if(g==1){
if(lim>1) res=(res+lim-1)%mod;
}
else res=(res+lim/g)%mod;
}return res;
}
int A,B,C;
vector<int> e[LGN];
inline int gcd(int a,int b){if(!b||!a) return a+b;int az=__builtin_ctz(a),bz=__builtin_ctz(b),z=(az>bz)?bz:az,t;b>>=bz;while(a) a>>=az,t=a-b,az=__builtin_ctz(t),b=a<b?a:b,a=t<0?-t:t;return b<<z;}
inline bool chk(int x,int d){
int p=x,tot=x;
while(p!=1&&tot){
int g=gcd(d,p);
if(g==1) break;
p/=g,tot--;
}
return p==1;
}
int g[LGN][N];
void solve(){
A=read();B=read();C=read();
int lim=Lg(2,A),L=Lg(2,B),res=0;
for(int i=1;i<=lim;i++) res=(res+calc(i,A,B,C))%mod;
write((C+res)%mod);io.pc('\n');
}
signed main(){
for(int x=1;x<=62;x++){
for(int y=1;y<=62;y++) if(gcd(x,y)==1) fl[x][y]=1,e[x].pb(y);
}
for(int x=3;x<=60;x++){
L[x]=1;
for(;qpow(L[x],x)<=Lim;L[x]++) ;
for(int i=1;i<=L[x];i++) pw[x][i]=qpow(i,x);
}
for(int x=1;x<=62;x++){
for(int y=1;y<=x;y++) if(x%y==0&&chk(x,y)){
f[x]=y;break;
}
}
int T=read();
while(T--) solve();
return 0;
}
没有精细实现,跑得很慢。