「模擬賽」暑期集訓CSP提高模擬10(7.28)

_yuen發表於2024-07-29

\(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\) 過大,所以考慮拿矩陣快速冪最佳化。有下列矩陣轉移:

\[ \begin{bmatrix} f_i & i+1 & 1 \end{bmatrix} = \begin{bmatrix} 10^k & 0 & 0 \\ 1 & 1 & 0 \\ 0 & 1 & 1 \end{bmatrix} \times \begin{bmatrix} f_{i-1} & i & 1 \end{bmatrix} \]

構造矩陣轉移即可。

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

相關文章