1. 程式人生 > 實用技巧 >6844. 【2020.11.02提高組模擬】旅途和生活(+簡要證明)

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;
}