其他大神的正解写的很好,我特此来发一篇乱搞做法。
本题解只作参考,主要指出骗分的方法和为什么乱搞做法通过率高(并给出一个乱搞做法),并不是实际意义上的正确做法。(但还是求管理员大大给过 QAQ)
赛时一个一个 subtask 骗分,骗着骗着就 AC 了,感觉好激动。本篇乱搞做法就围绕各 subtask 展开。
subtask 1
# subtask 2
观察到 $n$ 和锁圈的拨动范围极小,直接暴力 dfs 即可。
# subtask 3
直接枚举最大公约数,$\mathcal{O}(n)$ 判断是否可行,由于最大公约数肯定不超过 $\min_{i=1}^n r_i$,所以时间复杂度是可接受的。
# subtask 4
由于 $l,r$ 随机生成,所以其间包含的数期望会比较多,又因为 $k$ 比较小,大概率有解,直接计算任意一个不小于 $l_i$ 且不大于 $r_i$ 的数输出即可。
# subtask 5
由于存在 $l_i=r_i$,所以这个锁圈只能选择 $l_i$,所以最大公约数肯定为 $l_i$ 的因数。可以 $\mathcal{O}(\sqrt{l})$ 枚举因数并 $\mathcal{O}(n)$ 判断即可。这里有个小技巧,如果有多个 $l_i=r_i$ 时,我们可以直接记录这些 $l_i$ 的最大公约数并只枚举其因数即可。
# subtask 6
![](https://cdn.luogu.com.cn/upload/image_hosting/519emu4i.png)
玄学。赛时由于数据交水,直接暴力从 $k$ 开始枚举到 $\min_{i=1}^n r_i$ 并 $\mathcal{O}(n)$ 判断可过。加强了数据后就挂了,[会 T 一个点](https://www.luogu.com.cn/record/190711027)。
不妨想一想为什么会超时。我们发现有两个可能:
1. 最终合法的最大公约数过大。
2. 由于判断的顺序导致每一次判断都会 $\mathcal{O}(n)$ 跑满减慢程序运行。
争对第一点,由于公约数大,所以要么各个区间会产生重叠(每个区间包含这个数),要么导致 $n$ 减小、区间变小(每个区间包含这个数的两倍、三倍……可以发现因为最大公约数很大,所以区间数也相应会减少,虽然这么说并不严谨)。可以判断是否所有区间有重叠部分~~和精妙的玄学方法~~来解决问题。
对于第二点,我们略作思考,可以随机变换原序列的顺序,来尽量防止特意构造的数据把每一次 $n$ 次判断跑满。注意,这只能**减少**程序效率降低的概率,并不能**真正**地提高程序的效率。
综上所述,可得代码。
```cpp
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int T,n,k,chose[N];
struct node {
int l,r,id;
} a[N];
bool dfs(int x) {
if(x>n) {
int gcd=chose[1];
for(int i=2;i<=n;i++) gcd=__gcd(gcd,chose[i]);
if(gcd>=k) {
printf("Yes\n");
for(int i=1;i<=n;i++) printf("%d ",chose[i]);
printf("\n"); return true;
}
return false;
}
for(int i=a[x].l;i<=a[x].r;i++) {
chose[a[x].id]=i;
if(dfs(x+1)) return true;
}
return false;
}
int main() {
scanf("%d",&T);
while(T--) {
int mxl=0,mnl=1e9,mxr=0,mnr=1e9;
bool subtask=true;
int sbtask=0;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++) {
scanf("%d%d",&a[i].l,&a[i].r);
a[i].id=i;
if(a[i].r-a[i].l>4) subtask=false;
if(a[i].l==a[i].r) sbtask=__gcd(sbtask,a[i].l);
mxr=max(mxr,a[i].r),mnr=min(mnr,a[i].r);
mxl=max(mxl,a[i].l),mnl=min(mnl,a[i].l);
}
random_shuffle(a+1,a+1+n);
if(k==1) {
printf("Yes\n");
for(int i=1;i<=n;i++) chose[a[i].id]=a[i].l;
for(int i=1;i<=n;i++) printf("%d ",chose[i]);
printf("\n"); continue ;
}
if(mxr<=1000) {
bool ans=false;
for(int i=k;i<=mxr;i++) {
bool flag=true;
for(int j=1;j<=n;j++)
if(((a[j].l-1)/i+1)*i>a[j].r) {
flag=false; break ;
}
if(flag) {
printf("Yes\n");
for(int j=1;j<=n;j++) chose[a[j].id]=((a[j].l-1)/i+1)*i;
for(int j=1;j<=n;j++) printf("%d ",chose[j]);
printf("\n"),ans=true; break ;
}
}
if(!ans) printf("No\n");
continue ;
}
if(subtask) {
if(!dfs(1)) printf("No\n");
continue ;
}
if(sbtask) {
bool ans=false;
for(int i=k;i*i<=sbtask;i++)
if(sbtask) {
bool flag=true;
for(int j=1;j<=n;j++)
if(((a[j].l-1)/i+1)*i>a[j].r) {
flag=false; break ;
}
if(flag) {
printf("Yes\n");
for(int j=1;j<=n;j++) chose[a[j].id]=((a[j].l-1)/i+1)*i;
for(int j=1;j<=n;j++) printf("%d ",chose[j]);
printf("\n"),ans=true; break ;
}
}
if(!ans) printf("No\n");
continue ;
}
if(k<=5) {
printf("Yes\n");
for(int i=1;i<=n;i++) chose[a[i].id]=a[i].l/5*5+5;
for(int i=1;i<=n;i++) printf("%d ",chose[i]);
printf("\n"); continue ;
}
bool ans=false;
for(int i=k;i<=mnr;i++) {
bool flag=true;
for(int j=1;j<=n;j++)
if(!((a[j].l-1)/i<a[j].r/i)) {
flag=false; break ;
}
if(flag) {
printf("Yes\n");
for(int j=1;j<=n;j++) chose[a[j].id]=((a[j].l-1)/i+1)*i;
for(int j=1;j<=n;j++) printf("%d ",chose[j]);
printf("\n"),ans=true; break ;
}
}
if(!ans) printf("No\n");
}
return 0;
}
```