[AGC057D] Sum Avoidance
考虑到 \((S-i,i)\) 不会同时出现。
\(\forall x \geq (S+1)/2\) 是一组合法的构造方案,则 A 大小为 \((S-1)/2\)
接下来考虑对 \(\leq (S-1)/2\) 的集合进行选择,设他们构成了集合 B,可以列出若干条件:
- \(a\in B,b \in B,a+b\leq (S-1)/2\),则 \(a+b \in B\)
- \(B\) 不能凑出 \(S\)
不难发现这是充要条件。
考虑找到第一个加入的数,设为 \(d\),最大的时候也就 \(43\)。
考虑从小到大加入。
- 能被凑出,必须加入
- 不能被凑出,加入不会造成影响,加入。
考虑同余最短路,此时很容易发现第二种加入不超过 d 种。
同时发现,如果加入了第一种,对我们的 \(f\) 数组没有任何影响,所以我们先考虑算出 f 数组,然后计算对应的第 \(k\) 个。
由于是从小到大进行贪心,我们寻找下一个不能被凑出的,加入后不能凑出 \(S\) 的,最小的数。
假设加入的数为 \(v\),记 \(x=v \mod d\)
- 不能凑出,对应 \(v\lt f_x\)
- 不能凑出 \(S\),也就是更新后 \(f_{S \mod d}\gt S\),而加入后的转移柿为 \(f_{y}+iv \rightarrow f_{(y+ix)\mod d}\)
我们枚举对应的 \(x\),满足其对应的 \(f_x=\inf\),并求出其对应的最小 \(v\),对于每个 \(i\) 都有要求,也就对应了:
- \(f_{(S-ix)\mod d}+iv\gt S\),也就是 \(v\geq\lfloor \frac{S-f_{(S-ix)\mod d}}{i}\rfloor +1\)
找到所有 \(x\) 中最小的 \(v\),满足其小于等于 \((S-1)/2\),对应更新。
最后我们还要求出第 \(k\) 个,我们考虑二分 \(x\),最后我们能凑出来的,且小于 \((S-1)/2\) 的一定都在 \(B\) 里面,所以柿子为 \(\sum \limits_{i=0}^{d-1}(x-f_i)/d+[i\neq 0]\)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int ll
const ll inf=1e18+10;
int t,d;
ll S,K,f[50];
ll gcd(ll a,ll b){return !b?a:gcd(b,a%b);}
inline ll calc(ll x){
ll ans=0;
for(int i=0;i<d;i++)
if(f[i]<=x)ans+=(x-f[i])/d+1;
return ans-1;
}
signed main(){
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&S,&K);
if(K>(S-1)/2){puts("-1");continue;}
for(d=1;S%d==0;d++);
for(int i=1;i<d;i++)f[i]=inf;f[0]=0;
while(1){
int mv=inf;
for(int x=1;x<d;x++)
{
int v=0;
for(int i=1;i<d;i++) v=max(v,(S-f[((S-x*i)%d+d)%d])/i+1);
while(v%d!=x) v++;
if(v>=f[x]) continue;
mv=min(mv,v);
}
if(mv>(S-1)/2) break;
f[mv%d]=mv;
for(int i=0,gd=__gcd(mv,d);i<gd;i++)
{
for(int t=i,c=0;c<2;c+=(t==i))
{
int nxt=(t+mv)%d;
f[nxt]=min(f[nxt],f[t]+mv),t=nxt;
}
}
}
if(calc((S-1)/2)>=K){
ll l=1,r=(S-1)/2;
while(l<r){
ll mid=(l+r)>>1;
if(calc(mid)<K)l=mid+1;
else r=mid;
}
printf("%lld\n",l);
}else{
ll l=(S+1)/2,r=S-1;
while(l<r){
ll mid=(l+r)>>1;
if((S-1)/2-(S-1-mid-calc(S-1-mid))<K)l=mid+1;
else r=mid;
}
printf("%lld\n",l);
}
}
}