Codeforces Round #752 div1 ABC
A. Di-visible Confusion
题意
给一个长度为\(n\)的数组\(a\),当\(a_i\)不被\(i+1\)整除时,可以将\(a_i\)从数组中移除,后面剩余的元素向前递补(下标-1)。
问是否能把数组删空。
思路
数组\(a\)能被删空,等价于
1)数组\(a[1:n-1]\)能被删空,且
2)\(a[n]\)能被\(2, 3, \dots, n+1\)中的至少一项整除。
证明
显然1)是必要条件;
在1)成立的前提下,原命题是否成立取决于\(a[n]\)能否被移除;
在删空\(a[1:n]\)的过程中,\(a[n]\)的下标会从\(n\)递减到1,只要有一个满足条件的时刻,我们就可以将其移除。
证毕。
所以原问题可以递归地分解为求
\[\bigwedge_{i=1}^{n}(\bigvee_{j=2}^{i+1}j \nmid a[i]) = \bigwedge_{i=1}^n \overline{\bigwedge_{j=2}^{i+1}j \mid a[i]} = \bigwedge_{i=1}^n \mathrm{LCM}(2, 3, \dots, i+1) \mid a[i]
\]
从前往后扫一遍前缀LCM即可
B. Moderate Modular Mode
题意
给两个偶数\(x, y \in [2, 10^9]\),求\(n \in [1, 2 \times 10^{18}], s.t. n \% x = y \% n\)
思路
若\(x > y\),令\(n = x + y\)
否则令\(n = y - \frac{y \% x}{2}\)
C. Extreme Extension
题意
太长懒得讲了。。
思路
对于任意一个subarray,当前项大于后项时,将前项拆成小于等于后项的若干项,拆了前项,可能前项的前项又不合法了,于是继续拆……所以就从后往前拆。
拆的时候讲究贪心。每次拆分要最小化碎片数量,同时要尽可能均匀地拆分。拆的不均匀显然不优。
这样拆的话,每一项的拆分方式只有\(\sqrt{m}\)种是有效的,比如\(5=1+1+1+2\)这种拆法会被舍弃,因为\(5=1+2+2\)更优。
那就在\(n\sqrt{m}\)个状态上\(dp\),转移复杂度\(O(1)\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void fr(int &x){
char ch;
while(scanf("%c",&ch),ch<'0'||ch>'9');
x=ch-'0';
while(scanf("%c",&ch),ch>='0'&&ch<='9')x=x*10+ch-'0';
}
const int mod=998244353;
const int N=100010;
int a[N],n;
int dp[2][N];
int main(){
int T;
fr(T);
int ca=0;
while(T--){
fr(n);
for(int i=1;i<=n;++i)fr(a[i]);
int ans=0;
for(int i=1;i<=n;++i){
int bt=i&1;
if(i>1){
int k=(a[i-1]+a[i]-1)/a[i];
int r=(a[i-1]+k-1)/k;
ans+=dp[bt^1][r];
if(ans>=mod)ans-=mod;
}
for(int bd=a[i];bd;){
int k=(a[i]+bd-1)/bd;
int l=a[i]/k,r=(a[i]+k-1)/k;
dp[bt][r]=1ll*(k-1)*i%mod;
if(i>1){
int kk=(a[i-1]+l-1)/l;
int rr=(a[i-1]+kk-1)/kk;
dp[bt][r]+=dp[bt^1][rr];
if(dp[bt][r]>=mod)dp[bt][r]-=mod;
}
bd=r-1;
}
}
printf("%d\n",ans);
}
return 0;
}