\(145pts,Rank 10\),眾數分。
數學專題模擬賽%%%
總結寫前面:
1. 線性遞推式複雜度過大考慮矩陣快速冪最佳化;
2. T1 長時間切不了就先跳,先把所有題看一遍,拿分為主。
賽時記錄
正常開 T1,期望數學題,大概讀懂了,手模下小樣例,模了一遍又一遍,“我並不認為樣例是對的”,跳了(很正確的決定)。
T2,貌似也只會個 \(25pts\) 暴力,不過看起來挺可做的,先打了暴力,想著能不能找到規律,畢竟 \(n<=10^{18}\),好吧,並不可以。
T3,又是數學,推式子題,好熟悉的式子,莫比烏斯反演,不會...,\(O(n^2 \log n)\) 可以拿 \(10pts\) 暴力,額...思考,回憶關於莫比烏斯反演以及雙西格瑪後面挪到前面。
不小心發現小孩哥們在打水題比賽,報名了一下,哇,好水,用了兩分鐘切了 T1、T2,爽。誒, IOI 賽制的,看排行榜,E 題還沒人 AC,拿個首 A 我就跑,打表 AC 完發現首 A 被搶了,氣!他們還挺牛,現在就剩 C 題沒人 A 了,看 C 題,牛棚回聲,這我熟悉啊,三分鐘 A 了,發現首 A 又有人搶了!誒,不過怎麼 Rank 1 了,感覺大事不妙,不會被發現吧,溜了溜了。
大概兩分鐘之後,huge:(叫我名)過來。
走過去,看見 Delov 學長在旁邊,芭比Q,猜到是被發現了,被 D 了一頓。然後回來乖乖打比賽坐牢。
打了 T3 暴力,真不會了,開 T4 看看吧,!!不是,原來簽到題放 T4 了,迅速切了,然後由於這一場就會這一題,萬一再掛就祭了,於是打了個暴力跑對拍,十分鐘沒拍到 WA 的點,放心了。
回去看了下小孩哥模擬賽的排行榜,發現自己成績被取消了,重新整理一下,比賽頁面也看不見了。。。
之後就是在 T1 模樣例仍然覺得樣例不對,T2 想各種可能做法,T3 使勁回憶、卡常 之間來回跳,三道題正解都無果,不過 T3 記憶化一下,發現可以最佳化到 \(O(n^2)\),\(20pts\) 了,再度卡常,把四個 if
判斷換成了三目運算子,(一句話裡面套了五六對括號)。現在 \(145pts\) 了,剩下時間,一直坐牢了?。
我也完結撒花?
B.速度型高松燈 \(25pts\)
矩陣快速冪?,還真不會這個了,矩陣乘?,咋用啊,學過我記得,但學啥了呀。不是,矩陣乘法為啥這樣乘啊......
哎,填坑 ing,看到之前提高組某一塊的專題,好多都忘了,之前挖的坑現在果然還是要親手填。
正解:
易得:\(f_i = 10 ^ k \times f_{i-1} + i\),很線性的一個遞推式,但 \(n\) 過大,所以考慮拿矩陣快速冪最佳化。有下列矩陣轉移:
構造矩陣轉移即可。
code:
#include <bits/stdc++.h>
typedef unsigned long long ull;
#define ull __int128
using namespace std;
const int N = 5;
long long n; int m;
struct matrix{
int H, L; ull a[N][N];
void zero(){
memset(a, 0, sizeof a);
}
void one(){
zero();
for(int i=1; i<=H; i++) a[i][i] = 1;
}
void resize(int x, int y){
H = x, L = y;
}
matrix operator * (const matrix &A) const{
matrix res;
res.zero(); res.resize(H, A.L);
for(int i=1; i<=3; i++){
for(int j=1; j<=3; j++){
for(int k=1; k<=3; k++){
res.a[i][j] = (res.a[i][j] + a[i][k] * A.a[k][j] % m) % m;
}
}
}
return res;
}
}A;
matrix qpow(matrix X, ull b){
matrix res;
res.resize(X.H, X.L); res.one();
while(b)
{
if(b & 1) res = res * X;
X = X * X;
b >>= 1;
}
return res;
}
ull Mont_Mary(ull x, ull b){
ull a = x, res = 1;
while(b)
{
if(b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
int main(){
// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin>>n>>m;
ull x = n; int cnt = 0;
while(x) x /= 10, cnt++;
A.resize(1, 3); A.a[1][2] = A.a[1][3] = 1, A.a[1][1] = 0;
matrix base; base.resize(3, 3);
ull num = 9;
for(int i=0; i<cnt; i++){
ull k = num / 9 * 10;
base.one(); base.a[2][1] = base.a[3][2] = 1, base.a[1][1] = k;
if(i == cnt - 1) break;
A = A * qpow(base, num);
num *= 10;
}
A = A * qpow(base, n - Mont_Mary(10, cnt-1) + 1);
int ans = A.a[1][1];
cout<<ans;
return 0;
}
C.力量型高松燈 \(20pts\)
聽說這是學長讓我們學習莫反的把戲,不贊同 但確實有效果
正解:
我並不想寫這個式子過了
D.高松燈 \(100pts\)
水題放最後,差點進坑,本來打到 T3 我可能就要耗死了,還好看了眼 T4。
正解:
兩種情況,一個是數自己,一個是首位數 \(-1\),其他位全都為 \(9\)。
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 998244353;
int n;
int num[20];
signed main(){
// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin>>n;
int x = n, cnt = 0, sum = 0;
while(x)
{
num[++cnt] = x % 10;
sum += num[cnt];
x /= 10;
}
int s = (cnt - 1) * 9 + num[cnt] - 1;
cout<<max(s, sum);
return 0;
}