T1
原题:起床困难综合症
T2
貌似是一个叫做 ( m{Insertion DP}) 的东西,也就是插入式 ( m{DP})
T3
思维神仙题
首先观察这题的本质就是 (0/1) 移动,最后要移动出来的位置
然后是最神奇的一个地方:
构造一个矩阵 (B) 表示每个位置每次的移动情况
如果 (B_{i,j}) 为 (1) 那么表示第 (i) 个位置在第 (j) 次和前面交换了
当然数据范围并不允许我们这么搞,所以要考虑优化它
我们观察这个矩阵在同一列上的两个相邻的数字的一致性,如果它被交换了,那么两个数字都是 (1)
同理不交换的情况
所以这些数字是可以被缩下来的
然后这东西可以考虑用一个双端队列维护它的数字
因为数据范围的原因,我们考虑在双端队列里面维护 (0) 的段
记录 (0) 出现在当前段的左右端点
对于B矩阵,我们把它压成一个序列用 (deque) 来维护(原理上面简述了)
然后更新的时候就是如果当前的量是 (0) 那么把队列首的 (0) 改成 (1)
如果当前的量是 (1) 那么就把序列后移一个位置,然后前面再添加一个 (0)
所以每个 (1) 最后出现的位置就是 (i) 减掉前面的 (1) 的个数
const int N=3e6+10;
int a[N],n,T,delt,sum,s[N];
struct node{int st,ed;};
deque<node> q;
signed main(){
n=read(); T=read(); rep(i,1,n) a[i]=read();
for(reg int i=1;i<=n;++i){
if(!a[i]){
if(q.size()&&q[0].st==1-delt){
if(q[0].ed+delt<T) q[0].ed++;
else continue;
}else q.push_front((node){1-delt,1-delt});
sum++;
if(q.size()>1&&q[0].ed==q[1].st-1){
node tmp=(node){q[0].st,q[1].ed};
q.pop_front(); q.pop_front();
q.push_front(tmp);
}
}else{
s[i-sum]=1;
if(q.size()){
node now=q.back(); q.pop_back();
delt++; sum-=now.ed-now.st+1;
now.ed=min(now.ed,T-delt);
if(now.ed-now.st+1){
sum+=now.ed-now.st+1;
q.push_back(now);
}
}
}
}
for(reg int i=1;i<=n;++i) putchar(s[i]+'0'),putchar(' '); puts("");
return 0;
}
真是个神仙题
T4
首先观察出来每个车只能有两种情况或者三种情况,那么直接上 (2-sat)
对于每个 (x) 枚举一下就好了
所以相对来说比较难写(记得要建反向边)