題目描述
小 c 數學成績優異,於是老師給小 c 留了一道非常難的數學作業題:
給定正整數 n 和 m,要求計算 concatenate (1 .. n) mod m 的值,其中 concatenate (1 ..n)是將所有正整數 1, 2, …, n 順序連線起來得到的數。例如,n = 13, concatenate (1 .. n)=12345678910111213.小c 想了大半天終於意識到這是一道不可能手算出來的題目,於是他只好向你求助,希望你能編寫乙個程式幫他解決這個問題。
輸入輸出格式
輸入格式:
從檔案input.txt中讀入資料,輸入檔案只有一行且為用空格隔開的兩個正整數n和m,其中30%的資料滿足1≤n≤1000000;100%的資料滿足1≤n≤1018且1≤m≤109.
輸出格式:
輸出檔案 output.txt 僅包含乙個非負整數,表示 concatenate (1 .. n) mod m 的值。
輸入輸出樣例
輸入樣例#1:
13 13
輸出樣例#1:
4首先寫出遞推關係式:令s[i]為前i個數連線得到的數,c(i)表示i的位數,有s[i]= 10^c(i)+s[i-1]+i;
c(i)隨i變化,無法在轉移矩陣t中表示。如果c(i)固定,就可以套用矩陣快速冪的方法進行優化了!
考慮位數隨著i的變化最多隻會變化18次,因此可以按位數分段進行矩陣快速冪。
列舉位數,那麼有:
* 1, 1 ,0 =
1, 1 ,1}
這裡在狀態矩陣中加了乙個永遠為1的值,用於輔助i每次加一。
將多位數按每次加數時前乙個數所乘的10的個數分為10-99,100-999。。。的數字段,方便進行矩陣乘法 。
實現**時套模擬矩陣乘法模板和快速冪模板即可。
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
ll n,m,s[3][3]={},t[3][3]={};
void mmul(ll a[3][3],ll b[3][3],ll s[3][3])//模擬矩陣乘法
;//此處a和s是同一陣列,必須開乙個陣列作中轉站(而不是像在過載運算子中結果陣列是獨立的,不受乘數影響)
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
tmp[i][j]=(tmp[i][j]+(a[i][k]%m)*(b[k][j]%m))%m;//兩個長整型數相乘,一定要分別取餘,否則會爆負數(超範圍了)
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
s[i][j]=tmp[i][j];//在不影響乘數的前提下得出結果
}void cal(ll t,ll last)
}int main()
cal(t,n);//如果n<10,就說明每次加數時只要進一位即可
printf("%lld",s[2][0]);
return 0;
}
洛谷 P3216 HNOI2011 數學作業
最近學了矩陣,kzj大佬推薦了我這一道題目。乍一眼看上去,沒看出是矩陣,就隨便打了乙個暴力,30分。然後仔細分析了一波,發現蠻簡單的。結果全wa了,先看看下面的錯誤分析吧!首先,設f n 為最終答案,易得出 f n f n 1 10 n 然後魔改一下 f n f n 1 10 n 1 begin 1...
洛谷P3216 HNOI2011 數學作業
小 c 數學成績優異,於是老師給小 c 留了一道非常難的數學作業題 給定正整數 n 和 m,要求計算 concatenate 1 n mod m 的值,其中 concatenate 1 n 是將所有正整數 1,2,n 順序連線起來得到的數。例如,n 13,concatenate 1 n 123456...
洛谷 P3197 HNOI2008 越獄
來來來,日常水一篇 滑稽 監獄有連續編號為1 n的n個房間,每個房間關押乙個犯人,有m種宗教,每個犯人可能信仰其中一種。如果相鄰房間的犯人的宗教相同,就可能發生越獄,求有多少種狀態可能發生越獄 輸入格式 輸入兩個整數m,n.1 m 10 8,1 n 10 12 輸出格式 可能越獄的狀態數,模1000...