给一个拥有n个元素、可能含“?”的序列,通过构造使得所有数的绝对值之和最小,同时使得序列的连续的k项之和是严格递增的。
题目传送门
要满足连续K项和递增,即a[1]+a[2]+……+a[k]<a[2]+a[3]+……+a[k+1]<……<a[n-k+1]+a[n-k+2]+……+a[n]
只需:a[1]<a[k+1]<a[2*k+1]<……
a[2]<a[k+2]<a[2*k+2]<……
……
一开始想到的是枚举起点从1到n-k+1,终点到n。统计出现?的次数,每当出现一个非?的数时,求出之前所有?的值。(具体求法是:先求满足要求的最小值,即最左端?的值,要使绝对值之和最小,则之后的数在前面的基础上+1即可。)
但这样枚举的话,会出现问题,比如下面这种情况:
4 3
? ? ? ?
这里并未出现非?的数,因此会出错。
于是想到在输入完n个数后,再在其末尾添加k个大数inf+1,枚举终点范围变为n+k,然而这样还是无法解决问题。因为起点的枚举范围是1到n-k+1,也就是说,范围不够,这样枚举的话,有些值是无法求到的,比如上面的样例,第三个?就无法求出。起点的枚举范围应该为1到k,这样可保证求出所有的?的值。
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
char s[20];
int a[200005];
int main()
{
int n,k,i,j;
scanf("%d%d",&n,&k);
for(i=1;i<=n;++i)
{
scanf("%s",s);
if(s[0]=='?') a[i]=inf;
else sscanf(s,"%d",&a[i]);
}
for(i=n+1;i<=n+k;++i)
{
a[i]=inf+1;
}
for(i=1;i<=k;++i)
{
int cnt=0,pre=-inf;
for(j=i;j<=n+k;j+=k)
{
if(a[j]==inf) ++cnt;
else
{
if(a[j]-pre<=cnt)
{
puts("Incorrect sequence");
return 0;
}
int num=max(pre+1,min(-cnt/2,a[j]-cnt));
for(int t=cnt;t>0;--t) a[j-t*k]=num++;
cnt=0;
pre=a[j];
}
}
}
for(i=1;i<n;++i) printf("%d ",a[i]);
printf("%d\n",a[i]);
return 0;
}