do_while_true

一言(ヒトコト)

「题解」Codeforces 1612F Armor and Weapons

首先可以不管套件,假定 \(n<m\),那么答案不超过 \(\mathcal{O}(\log n+\frac{m}{n})\),也就是先倍增把 \(n\) 造出来,然后一步步造 \(m\)

答案这么小,那么常见的套路就是把答案放进复杂度里。

然后考虑一个 dp,假设当且在第 \(o\) 轮,令 \(f_i\) 为手中最牛逼的盔甲是 \(i\),能够拿到最牛逼的武器是 \(f_i\),想要 dp 出第 \((o+1)\) 轮的 \(f'\)

不用套件的转移,购买盔甲是 \(f'_j\gets f_i,i\leq j\leq i+f_i\),购买武器是 \(f'_i\gets f_i+i\)

用套件的话,那么一定是用 \(i\)\(f_i\),要不然不会更优,所以也能类似转移。

通过打 tag 然后从后往前取 max 可以做到单次 \(\mathcal{O}(n)\) 转移,那么时间复杂度就是 \(\mathcal{O}(n\log n+m)\)

const int N=200010;

int n,m,q,x,y,ans,f[N],g[N],fl;
map<int,int>vis[N];

void solve(){
	read(n,m,q);
	if(n>m)swap(n,m),fl=1;
	while(q--)read(x,y),fl?swap(x,y),0:0,vis[x][y]=1;
	f[1]=1;
	for(;f[n]<m;++ans){
		for(int i=1;i<=n;i++)if(f[i]){
			int k=vis[i][f[i]];
			cmax(g[min(n,i+f[i]+k)],f[i]);
			cmax(g[i],min(m,i+f[i]+k));
		}
		for(int i=n;i>=1;i--)f[i]=max(g[i],f[i+1]),g[i]=0;
	}
	cout << ans << '\n';
}
posted @ 2022-11-05 14:13  do_while_true  阅读(22)  评论(0编辑  收藏  举报