牛客練習賽44----D-小y的盒子

首先發出題目鏈接:
鏈接:https://ac.nowcoder.com/acm/contest/634/D
來源:牛客網
涉及:擴展歐拉定理,快速冪


題目如下:
在這裏插入圖片描述
在這裏插入圖片描述
我去,題目又有求和,又是大數,果斷放棄


對於這個題目,首先需要一些數學思考

小y有兩組圖片
第一組(藍色)1 3 9 27 81…(3n-1
第一組(紅色)1 3 9 27 81…(3n-1

可惜所有卡片混亂在一起,在這些混亂的卡片中每個3n-1都有兩張卡片

每個3n-1可以化爲3進制的數字

比如1(1),3(10),9(100),81(10000)…

所有卡片數字的總和m即爲22222222222…2222(一共n個2)
證明:3n-1前n項和化爲3進製爲11111111(一共n個1),回合卡片中每個數字都有紅色和藍色兩張卡片,所以m等於3n-1前n項和的2倍)

現在的問題是組合卡片,求使得卡片和爲1到m的所有卡片組合方案的和


從1到m每一個數字的都可以化爲三進制數字h,每一個三進制數字h都有n位(不足n位補0)

然後考慮三進制數h每一位上面的數字(0,1,2):
當第i位上的數字爲1時,表示這一位上需要1張3i-1數字的卡片(有且只有“紅色”和“藍色”兩種選擇);
當第i位上的數字爲2時,表示這一位上需要2張3i-1數字的卡片(有且只有“紅色和藍色都要”這一種選擇);
當第i位上的數字爲0時,表示這一位上不需要3i-1數字的卡片(有且只有“不需要卡片”這一種選擇);
(ps:此時有人會說當第i位上的數字不爲0時,不能由多張3j(j<i-1)的卡片加起來得到嗎?
然而,當第i位數字不爲1時,你把3j(j<i-1)所有卡片加起來也湊不齊第i位的數字

這個三進制數h的n個位置上的每一位數字都有可能是1,2或者3。爲1時,會有兩種選擇;爲2或者0時,會有一種選擇。

假設有i個位置是1,j個位置是2,n-i-j個位置是0

則當n=n0時,所有的選擇爲
in0(Cn0i2ijn0i(Cnij1jCn0ijn0ij1n0ij))\sum^{n_{0}}_{i}(C^{i}_{n_{0}}*2^{i}*\sum^{n_{0}-i}_{j}({C^{j}_{n-i}*1^{j}*C^{n_{0}-i-j}_{n_{0}-i-j}*1^{n_{0}-i-j})})
=in0(Cn0i2ijn0iCn0ij)\sum^{n_{0}}_{i}(C^{i}_{n_{0}}*2^{i}*\sum^{n_{0}-i}_{j}{C^{j}_{n_{0}-i}})
=in0(Cn0i2i2n0i)\sum^{n_{0}}_{i}(C^{i}_{n_{0}}*2^{i}*2^{n_{0}-i})
=in0(Cn0i2n0)\sum^{n_{0}}_{i}(C^{i}_{n_{0}}*2^{n_{0}})
=2n0in0Cn0i2^{n_{0}}*\sum^{n_{0}}_{i}C^{i}_{n_{0}}
=4n04^{n_{0}}
(ps:inCni=2n)(ps:\sum^{n}_{i}C^{i}_{n}=2^{n})

然後n不等於0,所以結果還要減去1,然後對p求餘,於是所有的方案和爲
(4n1) mod p (ps:1n10100000)(4^{n}-1) mod p (ps:1\le n\le10^{100000})


對公式變形:
(4n1) mod p=((4n mod p)1+p) mod p(4^{n}-1) mod p=((4^{n} mod p)-1+p) mod p

由於n非常大,根據擴展歐拉定理可知
4n mod p=4((n mod ϕ(p))+ϕ(p)) mod p4^{n} mod p=4^{((n mod \phi(p))+\phi(p))} mod p

(ps:ϕ(p)\phi(p)是歐拉函數,ϕ(p)\phi(p)的值爲1~p中與p不互質的數的個數,求歐拉函數ϕ(p)\phi(p)是有公式的,不知道歐拉函數歐拉定理可以看看其他我的博客
通過公式求歐拉函數ϕ(p)\phi(p)值的代碼如下
注意把(1-1.0/i)值化爲浮點類型,如果是整型就錯了,後來再化成long long類型

ll getDivisor(){
	ll sum=p;
	int i;
	ll p1=p;
	for(i=2;i*i<=p1;i++){
		if(p1%i==0)	sum=ll1*sum*(1-1.0/i);
		while(p1%i==0)	p1=p1/i;
	}
	if(p1!=1)	sum=ll1*sum*(1-1.0/p1);
	return sum;//sum爲歐拉函數的值
}

所以現在只用通過大數求模的方式求出(n mod ϕ(p))(n mod \phi(p)),得到((n mod ϕ(p))+ϕ(p))((n mod \phi(p))+\phi(p))之後用快速冪(4((n mod ϕ(p))+ϕ(p)) mod p)(4^{((n mod \phi(p))+\phi(p))} mod p),關於大數求模可以看看其他博客。
通過大數求模得到((n mod ϕ(p))+ϕ(p))((n mod \phi(p))+\phi(p))的值

ll getPow(){
	stream<<str;//stream爲stringstream類型
	ll sum=0;
	char c;
	while(stream>>c)
		sum=(10*sum+c-'0')%divisor;
	stream.clear();
	return sum+divisor;//其中sum爲n對歐拉函數求餘的值,divisor是歐拉函數的值
}

然後是快速冪的代碼

ll qSort(){
	ll x=4,sum=1;
	while(pow1!=0){
		if(pow1%2!=0)	sum=sum*x%p;
		pow1=pow1>>1;
		x=x*x%p;
	}
	return sum-1+p;//sum是4的n次方的值(sum-1+p)對p取餘即爲答案
}

舉個例子

當n=13,p=15
p的質因子爲2和3和5,則ϕ(p)=p(11/2)(11/3)(11/5)=4\phi(p)=p*(1-1/2)*(1-1/3)*(1-1/5)=4
(n mod ϕ(p))+ϕ(p)=5(n mod \phi(p))+\phi(p)=5
4((n mod ϕ(p))+ϕ(p)) mod p=44^{((n mod \phi(p))+\phi(p))} mod p=4
即答案爲4(例子很簡單,只要你實現了大數取模就可以


代碼如下:

#include <iostream>
#include <algorithm> 
#include <string>
#include <sstream>
#define ll1 (ll)1
using namespace std;
typedef long long ll;
stringstream stream;//輸出流,用來方便地將一個字符串拆成一個個字符
ll p,divisor,pow1; //p是題目所給,divisor是存p的質因子的個數,pow1是用來存冪數
string str;//用來存n的值
int t;
ll qSort(){//這個qsort寫錯了,不是快排,是快速冪,求4的n次方
	ll x=4,sum=1;
	while(pow1!=0){
		if(pow1%2!=0)	sum=sum*x%p;
		pow1=pow1>>1;
		x=x*x%p;
	}
	return sum-1+p;
	//因爲要算(4^n-1)%p的值,而(4^n-1)%p=(4^n%p-1+p)%p,所以要返回4^n%p-1+p,即返回sum-1+p
}
ll getPow(){//利用歐拉定理,將大數冪的指數的值降到10^9以下。
	stream<<str;//將字符串存到stream去
	ll sum=0;
	char c;
	while(stream>>c)//每次從stream拿一個字符出來
		sum=(10*sum+c-'0')%divisor;//大數求餘
	stream.clear();
	return sum+divisor;
}
ll getDivisor(){//分解質因子,得到p的質因子的個數
	ll sum=p;
	int i;
	ll p1=p;
	for(i=2;i*i<=p1;i++){
		if(p1%i==0)	sum=ll1*sum*(1-1.0/i);
		while(p1%i==0)	p1=p1/i;
	}
	if(p1!=1)	sum=ll1*sum*(1-1.0/p1);
	return sum;
}
int main(){
	cin>>t;
	while(t--){
		cin>>str>>p;
		divisor=getDivisor();
		pow1=getPow();
		cout<<qSort()%p<<endl;
	}
	return 0;
}
發佈了49 篇原創文章 · 獲贊 91 · 訪問量 3986
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章