Solution: 題解 USACO2020JAN-Silver Loan Repayment


在這里解釋一下二分內judge()的操作方式

首先一定是二分\(x\),不必多說

但是如果真的一天天掃過去,每次judge()是\(O(k)\)的,明顯超時

所以在judge()時會使用類似除法分塊的方法

假設現在剩下了\(r\)的欠債,還剩\(t\)

循環退出條件:\(r\leqslant0||t==0\),這時直接通過\(r\leqslant0\)的成立與否判斷\(x\)的成立與否

那么\(y=\lfloor\frac{r}{x}\rfloor\)

如果\(y\leqslant m\),那么直接就以\(m\)為每天的還債量,於是\(r-=tm,t=0\)

否則就計算一下會有連續多少天的每日還債量是\(y\),假設這種情況持續\(a\)天,那么可以知道在\(a-1\)天之后的還債量\(=y\),而\(a\)天之后的還債量\(<y\)

於是有方程\(\lfloor\frac{r-(a-1)y}{x}\rfloor=y,\lfloor\frac{r-ay}{x}\rfloor<y\)

改為不等式:\(\frac{r-(a-1)y}{x}\geqslant y,\frac{r-ay}{x}<y\)

變形:\(a\leqslant\frac r y-x+1,a>\frac r y-x\)

因為\(a\)是正整數,所以\(a=\lfloor\frac r y-x+1\rfloor\)

於是在之后的連續\(a\)天,花費都是\(y\)

那么就可以快速把答案“跳”出來了

Time complexity: \(O(n^\frac{1}{2}\log n)\)(后面有證明)

Memory complexity: \(O(1)\)

細節請見代碼(代碼中用\(rm\)代替\(r\)

//This program is written by Brian Peng.
#pragma GCC optimize("Ofast","inline","no-stack-protector")
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define Rd(a) (a=read())
#define Gc(a) (a=getchar())
#define Pc(a) putchar(a)
int read(){
	register int x;register char c(getchar());register bool k;
	while(!isdigit(c)&&c^'-')if(Gc(c)==EOF)exit(0);
	if(c^'-')k=1,x=c&15;else k=x=0;
	while(isdigit(Gc(c)))x=(x<<1)+(x<<3)+(c&15);
	return k?x:-x;
}
void wr(register int a){
	if(a<0)Pc('-'),a=-a;
	if(a<=9)Pc(a|'0');
	else wr(a/10),Pc((a%10)|'0');
}
signed const INF(0x3f3f3f3f),NINF(0xc3c3c3c3);
long long const LINF(0x3f3f3f3f3f3f3f3fLL),LNINF(0xc3c3c3c3c3c3c3c3LL);
#define Ps Pc(' ')
#define Pe Pc('\n')
#define Frn0(i,a,b) for(register int i(a);i<(b);++i)
#define Frn1(i,a,b) for(register int i(a);i<=(b);++i)
#define Frn_(i,a,b) for(register int i(a);i>=(b);--i)
#define Mst(a,b) memset(a,b,sizeof(a))
#define File(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout)
int n,k,m,l(1),r,md;
bool jdg(int x);
signed main(){
	r=Rd(n),Rd(k),Rd(m);
	while(l<=r)jdg(md=(l+r)>>1)?l=md+1:r=md-1;
	wr(l-1),exit(0);
}
bool jdg(int x){
	int y,a,rm(n),t(k);
	while(t&&rm>0){
		y=rm/x;
		if(y>m)a=min(rm/y-x+1,t),rm-=a*y,t-=a;
		else rm-=t*m,t=0;
	}
	return rm<=0;
}

現在是復雜度證明

每次judge()的時間消耗就是不同\(y\)值的數量,假設是\(d\)

那么最壞情況就是不同的\(y\)值分別是\(1,2,\cdots,d\),而且每個只出現一次

那么就有\(\sum_{i=1}^d i\geqslant n\),此時使\(d\)最小

利用等差數列求和公式:\(\frac{d(d+1)}{2}\geqslant n\)

\(d=\lceil (2n)^\frac{1}{2}\rceil\)時就滿足不等式

所以\(d=O(n^\frac{1}{2})\)

於是最終時間復雜度\(O(d\log n)=O(n^\frac{1}{2}\log n)\),可以AC


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM