A:其实就是找规律:
首先我们可以发现对于第一位不是1的话,我们要让第二位变为0必须满足第2位是第一位的倍数,同时第3位也是第一位的倍数,利用 8 16 4 可以发现对于第二位是第一位的倍数,我们可以将其变为和第一位相同此时第3位也和第1位联系起来了,假如有一位数不是第1位的倍数,那么他前面不管怎么变他都没机会变为0
B:观察题,也是找规律,我们可以发现对于第一位来说他的gcd只能是1,第二位gcd只能是1-2,排除1就是2,第三位同理,所以我们就在范围内找就好了i的倍数就好了
C:
刚开始还以为是利用后缀主席树维护每点变小是会对答案产出的影响,想了好久都没找到维护方式,最后仔细想想就发现我们的智商其实是没有什么用的,就可以在最后都用关掉,这就给我们一个启发,从后向前维护,假设最后我们智商是0,在逐渐向前变化:
#include<iostream>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn],n;
void solve()
{
int k;
cin >>n>>k;
for (int i = 1; i <= n; i++)
cin >> a[i];
int resn = 1;
a[n] = 1;//最后一个不要白不要
for (int i = n-1; i >= 1; i--){
if (a[i] > resn) {
resn++;//代表此时智商是被减小的地方
a[i] = 1;
}
else//此时直接白嫖
a[i] = 1;
if (resn > k)//最大值是k
{
resn = k;
a[i] = 0;
}
}
for (int i = 1; i <= n; i++)
cout << a[i];
cout << endl;
}
signed main()
{
int t;
cin >> t;
while (t--)
solve();
return 0;
}
D:比赛时候完全没有思路,根本想不到0可以直接优化掉, 这体现了做题时模拟数据的好处,他的证明在于,我们此时利用sum of a,每次操作后我们的sum of a 至少减少了n-1:
sum1=a[1]+a[2]+++++a[n];
sum2=a[n]-a[1];在a[1],a[2],a[3]存在时,sum至少下降n-1;
此时sum代表我们操作后n的最大值(n:a[i]>0的个数)
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
int l = 1;
for (int i = 1; i < n; i++) {
for (int j = n; j >= l; j--)a[j] -= a[j - 1];
a[i] = 0;//代表这个数已经被删掉了
sort(a + l, a + n + 1);//因为每次差分会出现很多0,我们将之前的0删去可以有效的减小排序的次数
while (a[l] == 0 && l <= n)l++;//将0删取
}
cout << a[n] << endl;
}
}
EF不是我现在可以动的题,等明年一定可以