https://vjudge.net/problem/UVA-1444
题目
你要去图书馆借书,但是书架挡住了你,你没法到图书管理员那里
所有书架都可以左右滑动,但是只能停稳在整数格的位置,于是你决定开辟一条通道
比如这两种方式,你需要推动3个书架。由于你太懒了,只想推动最少的书架。而且你不想走迷宫,只想开辟出一条直的通道。
第一行输出最少推动的书架数量
第二行按照升序输出在什么位置开辟通道需要推动这么多书架
行数>=1,1<=列数<=10^6,书架数+空位数<=2*10^7
时间限制5s
Sample Input
1 4 10 8 1 2 1 0 1 2 0 1 7 2 2 2 1 0 1 0 6 1 3 2 0 2 1 7 2 1 2 0 2 1 0
Sample Output
3 8 9
题解
比较坑,显然没法把所有格子都保存下来,只能保存一排格子。
依次计算每个位置向左推和向右推需要移动多少书架
用一个数组保存当前位置推到第i个空位需要移动多少书架,为了方便计算推多个空位,保存前缀和
那么问题就很简单了,直接模拟,顺便记忆一下哪些位置不能移动,时间复杂度$O(n^2)$……但是记忆一下就可以过时限
暴力乱写居然都过了
2009年欧洲中部区域赛的题目,输出格式没有说明,如果不加空格还会错
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #define REP(i,a,b) for(int i=(a); i<(b); i++) #define REPE(i,a,b) for(int i=(a); i<=(b); i++) #define PERE(i,a,b) for(int i=(a); i>=(b); i--) using namespace std; typedef long long ll; #define MAXN 1000007 unsigned long long ans[MAXN]; bool no[MAXN]; int a[MAXN], b[MAXN], lft[MAXN]; int r,l; inline void pro() { int n; scanf("%d", &n); REP(i,0,n) scanf("%d", &a[i]); int nowi=0, pos=0; b[0]=0; memset(lft,0x3f,sizeof(int)*l); REP(i,0,n) { if(a[i]==0) { nowi++; b[nowi]=b[nowi-1]; lft[pos]=0; pos++; } else { int opos=pos; pos+=a[i]; b[nowi]++; for(int c=pos-1, d=nowi-1; c>=opos && d>=0; c--, d--) { lft[c]=b[nowi]-b[d]; } } } nowi=0, pos=l-1; b[0]=0; PERE(i,n-1,0) { if(a[i]==0) { nowi++; b[nowi]=b[nowi-1]; lft[pos]=0; pos--; } else { int opos=pos; pos-=a[i]; b[nowi]++; for(int c=pos+1, d=nowi-1; c<=opos && d>=0; c++, d--) { lft[c]=min(lft[c], b[nowi]-b[d]); } } } REP(i,0,l) if(!no[i]) { ans[i]+=lft[i]; no[i]=lft[i]>=0x3f3f3f3f; } } inline void go() { scanf("%d%d", &r, &l); memset(ans,0,sizeof(unsigned long long)*l); memset(no,0,sizeof(bool)*l); REP(i,0,r) { pro(); } int now=0; unsigned long long nma=0x7fffffffffffffffull; REP(i,0,l) if(!no[i]) { if(ans[i]<nma) { nma=ans[i]; now=1; a[0]=i; } else if(ans[i]==nma) { a[now++]=i; } } printf("%llu\n", nma); REP(i,0,now) printf("%d ", a[i]); putchar('\n'); } int main() { int z; scanf("%d", &z); while(0<z--) { go(); } }