Codeforces Round #642 (Div. 3) 题解
A
序列是\(0,m,0,0,\cdots\)时有最优解。
特判一下\(n=1,2\)的情况。
int main()
{
int T=read();
while (T--)
{
ll n=read(),m=read();
if (n==1) puts("0");
else if (n==2) printf("%lld\n",m);
else printf("%lld\n",m*2);
}
return 0;
}
B
贪心的考虑,每次操作肯定会把\(a\)中最小的换成\(b\)中最大的,如果这样做没有收益那么就停下来。
int main()
{
int T=read();
while (T--)
{
n=read();m=read();
rep(i,1,n) a[i]=read();
rep(i,1,n) b[i]=read();
while (m--)
{
int id1=1,id2=1;
rep(i,2,n)
if (a[i]<a[id1]) id1=i;
rep(i,2,n)
if (b[i]>b[id2]) id2=i;
if (a[id1]>b[id2]) break;
swap(a[id1],b[id2]);
}
int ans=0;
rep(i,1,n) ans+=a[i];
printf("%d\n",ans);
}
return 0;
}
C
所有格子都集中到最中间的那个格子时有最优解。
枚举一下所需时间再乘一下格子数即可。
int main()
{
int T=read();
while (T--)
{
int n=read();
unsigned long long ans=0;
rep(i,1,(n-1)/2)
{
ans+=1ll*i*i*2*4;
}
printf("%llu\n",ans);
}
return 0;
}
D
用个堆维护当前的极长连续\(0\)区间即可。
struct node{int l,r;};
bool operator <(node p,node q)
{
if (p.r-p.l!=q.r-q.l) return p.r-p.l<q.r-q.l;
else return p.l>q.l;
}
priority_queue<node> q;
int n,a[200200];
int calc(int l,int r)
{
if ((r-l+1)&1) return (l+r)>>1;
else return (l+r-1)>>1;
}
int main()
{
int T=read();
while (T--)
{
n=read();
q.push((node){1,n});
int id=0;
while (!q.empty())
{
node now=q.top();q.pop();
int mid=calc(now.l,now.r);
a[mid]=(++id);
if (mid-1>=now.l) q.push((node){now.l,mid-1});
if (mid+1<=now.r) q.push((node){mid+1,now.r});
}
rep(i,1,n) printf("%d ",a[i]);puts("");
}
return 0;
}
E
(可能做复杂了)
把所有模\(k\)的余数相同的位置拿出来,那么其它位置首先要变成\(0\).
记拿出来的权区间长度为\(n\),且有\(m\)个\(1\),其前缀和为\(s_i\),枚举一下最后为1的区间\([l,r]\), 那么要求的就是\(\min(m-(s_r-s_{l-1})+(r-l+1)-(s_r-s_{l-1}))\), 即\(\min(m-2s_r+r+2s_{l-1}-(l-1))\).对后面哪个沿途取个\(\min\)即可,注意还要加上当前序列全为\(0\)时最优的情况。
int n,m,tot,k,a[1001000],s[1001000],all=0;
char str[1001000];
int calc(int md)
{
m=0;tot=0;
for (int i=md;i<=n;i+=k)
{
a[++tot]=(str[i]=='1');
m+=a[tot];
}
rep(i,1,tot) s[i]=s[i-1]+a[i];
int now=m,mx=0;
rep(r,1,tot)
{
now=min(now,m-s[r]*2+r+mx);
mx=min(mx,2*s[r]-r);
}
now+=all-m;
return now;
}
int main()
{
int T=read();
while (T--)
{
n=read();k=read();
scanf("%s",str+1);
int ans=n;all=0;
rep(i,1,n) all+=(str[i]=='1');
rep(i,1,min(n,k)) ans=min(ans,calc(i));
printf("%d\n",ans);
}
return 0;
}
F
一个显然的性质是如果\(a_{1,1}\)的值被确定了,那么沿途中每个位置的值都是确定的,即\(a_{i,j}=a_{1,1}+i+j-2\).
同时注意到如果最终的合法路径每个格子都被操作了至少一次,那么我们可以整体减少一次操作使其更优。
综合上面两个结论,就会发现最终\(a_{1,1}\)的取值只会有\(O(nm)\)个,枚举这个值然后跑dp就行了。
int n,m;
ll a[110][110],f[110][110];
ll work(ll st)
{
rep(i,0,n) rep(j,0,m) f[i][j]=1e18;
if (a[1][1]>=st) f[1][1]=a[1][1]-st;
rep(i,1,n) rep(j,1,m)
{
if ((i==1) && (j==1)) continue;
if (a[i][j]>=(st+i+j-2))
{
ll now=a[i][j]-(st+i+j-2);
f[i][j]=min(f[i-1][j],f[i][j-1])+now;
}
}
return f[n][m];
}
int main()
{
int T=read();
while (T--)
{
n=read();m=read();
rep(i,1,n) rep(j,1,m) a[i][j]=readll();
ll ans=4e18;
rep(i,1,n) rep(j,1,m) ans=min(work(a[i][j]-(i+j-2)),ans);
printf("%lld\n",ans);
}
return 0;
}