6844. 【2020.11.02提高組模擬】旅途和生活(+簡要證明)
題目描述
求\(low(a^n-b^n)\),T組詢問
a,b,n,t<=1e6,a>b
題解
兩個數相乘等於其提出二次冪後二次冪係數相加剩餘部分相乘(low(a)low(b)=low(ab)),所以考慮儘量化成乘積的形式
首先把ab的2次冪提出來,如果ab有偶數則為1,否則考慮打表
考場上打表發現剩餘部分的low不超4an,所以直接拆開乘即可,直接算\(2^{20}\)然後找lowbit,因為\(\%2^i\)一定包含\(\%2^j(i>j)\)的位
實際上題目後面給了提示不超ll,所以直接ull自然溢位即可
考慮直接算
結論:當n為奇數時\(ans=low(a-b)\),否則\(ans=low(a-b)low(a+b)low(n/2)\)
題解裡面並沒有給出證明其實給了打表,這裡簡單口胡一下
①n為奇數
因為\(a^n-b^n=(a-b)\sum_{i=0}^{n-1}a^ib^{n-1-i}\),後面有奇數項每項都為奇數,所以後面的貢獻是1,ans=\(low(a-b)\)
②n為偶數
\(a^n-b^n=(a-b)\sum_{i=0}^{n-1}a^ib^{n-1-i}\),由於n為偶數所以分別提出\(a^{n/2}\)和\(b^{n/2}\)
\(=(a-b)(a^{n/2}+b^{n/2})(a^{n/4}+b^{n/4})...(\sum_{i=0}^{n/2^k-1}a^ib^{n/2^k-1-i})\)
後面的n/k為奇數所以不用考慮,只需要證\(low((a^{n/2}+b^{n/2})(a^{n/4}+b^{n/4})...)=low(a+b)low(n/2)\)
分開考慮,由於\(n/2^k\)是奇數,所以對於其餘的實際上有\(a^c+b^c\),其中c為偶數
一個奇數可以寫成\(a2^k+1\)的形式,將其平方後有\(a^22^{2k}+a^{k+1}+1\),由於k至少為1所以奇數的平方模4餘1
(實際上是模8餘1,一直平方後分別模16、模32...餘1)
則兩個奇數平方相加後模4餘2,即只能提一個2出來,因此一共提了k-1個2,即\(low(n/2)\)
最後剩下一個\(a^c+b^c\),其中c為奇數,可以化成\((a+b)\sum_{i=0}^{c-1}a^ib^{c-i-1}\),後面有奇數項所以\(low(a^c+b^c)=low(a+b)\)
綜上,當n為偶數時\(log(a^n-b^n)=log(a-b)log(a+b)log(n/2)\)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define low(x) ((x)&-(x))
#define mod 1000000007
#define ll long long
#define file
using namespace std;
int T,i,j,k,l;
ll a,b,n,ans;
ll qpower(ll a,int b) {ll ans=1; while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
int main()
{
freopen("journey.in","r",stdin);
#ifdef file
freopen("journey.out","w",stdout);
#endif
scanf("%d",&T);
for (;T;--T)
{
scanf("%lld%lld%lld",&a,&b,&n);
ans=1;
while (!(a&1) && !(b&1)) a>>=1,b>>=1,ans<<=1;
ans=qpower(ans,n)%mod;
if ((a&1) && (b&1))
{
if (n&1) ans=ans*low(a-b)%mod;
else ans=ans*low(a-b)%mod*low(a+b)%mod*low(n/2)%mod;
}
printf("%lld\n",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}