# Dynamic Programming# String Manipulation# Math

d266 - 退休的福利

🔗 前往 ZeroJudge 原題

題目描述

題目描述了退休福利的計算方式:第一天得到 1 顆米,第二天得到 2 顆米,第三天得到 4 顆米,以此類推,每天得到的米數都是前一天的兩倍。要求計算第 N 天總共得到的米數。

解題思路

這道題的本質是計算一個等比數列的和,其中首項為 1,公比為 2,項數為 N。由於米數會非常大,直接使用數值型別可能會溢位。因此,程式碼使用字串來表示米數,並使用自定義的 add 函數來進行大數加法。程式碼預先計算了前 1000 天的米數,並將結果儲存在 ab 陣列中。a[i] 儲存第 i 天得到的米數(2的i-1次方),b[i] 儲存前 i 天得到的總米數。讀取輸入 n 後,直接輸出 b[n-1] 即可。

複雜度分析

  • 時間複雜度: O(N) (預計算部分,N <= 1000) + O(1) (查詢部分)
  • 空間複雜度: O(N) (儲存預計算結果的陣列)

程式碼

#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <iostream>
using namespace std;
string a[1001]={"1"},b[1001]={"1"};
inline string add(string x,string y){
	int xx[303]={0},xl(x.length()-1),i(0);
	string ans;
	for(;i<=xl;++i){
		xx[i]+=y[xl-i]+x[xl-i]-96;
		if(xx[i]>9){
			xx[i]-=10;
			++xx[i+1];
		}
	}
	++xl;
	if(!xx[xl])--xl;
	for(;xl>=0;--xl)
		ans+=xx[xl]+48;
	return ans;
}
inline void write(string x) {
	for(int i=0,xl=x.length();i<xl;++i)
		putchar_unlocked(x[i]);
	putchar_unlocked(10);
}
inline int read(){
	int a(0);
	char c('0');
	while(c>='0'){
		a=(a<<3)+(a<<1)+c-'0';
		c=getchar_unlocked();
	}
	return a;
}
int main(){
	int n;
	for(int i=1;i<1001;++i){
		a[i]=add(a[i-1],a[i-1]);
		b[i]=add(a[i],b[i-1]);
	}
	while(n=read())write(b[n-1]);
}

Discussion