首先,当发现全场不存在黑色帽子时,显然所有人都知道其是白色帽子,即必然离开

当第一轮时,若第$n$个人发现前面$n-1$个人全是白色时,其自己必然是黑色,必然离开

而第二轮时,若第$n-1$个人发现$n$没有离开,且前面$n-2$个人都是白色时,其自己必然是黑色(否则第$n$个人必然会在第一轮离开),其必然离开

而第三轮时,若第$n-2$个人发现$n$和$n-1$都没有离开,且前面$n-3$个人都是白色时,其自己必然是黑色(否则若第$n-1$个人必然会离开),其必然离开

以此类推,第一个离开的人即第一个黑色的人,假设其编号为$i$,其离开时间即为$n-i$

同时,在$i$之前的人也都知道其为白色,其都会离开

接下来的信息实际上是独立的,即无法利用到前面的信息,换言之会不断重复该过程

(具体的可以类似分析,这里就不再描述了)

例如,当$n=6$且$n$个人颜色依次为0 0 1 0 1 0,离开时间即依次为5 5 4 7 6 7

为了方便,我们需要用更严谨的语言来描述此过程——

令$c_{i}$为第$i$个数的颜色(0或1),$t_{i}$为第$i$个人离开的时间,则有
$$
\begin{cases}t_{i}=\sum_{1\le j\le i,c_{j}=1}n-j+1 & (c_{i}=1)\\t_{i}=t_{nex_{i}}+1&(c_{i}=0)\end{cases}
$$
(其中$nex_{i}$定义为$\min_{i\le j\le n,c_{j}=1}j$,若不存在$j$则定义为$n+1$,且约定$c_{n+1}=1$)

由此,对于$i<j$,若$t_{i}$和$t_{j}$已经确定,根据其关系不难确定一些$c_{i}$,即:

1.若$t_{i}\ge t_{j}+2$,无解(保证有解,即必然不存在此类情况)

2.若$t_{i}=t_{j}+1$,则$c_{j}=1$且$\forall i\le k<j,c_{k}=0$

3.若$t_{i}=t_{j}$,则$\forall i\le k\le j,c_{k}=0$或$\exists i<k<j,c_{k}=1$且$\sum_{k=i}^{n}c_{k}=1$

4.若$t_{i}<t_{j}$,则上述情况都不满足

(注意$t_{n+1}$一定未被确定,因此上述结论成立)

由此,我们将所有非0的$t_{i}$取出,将其划分为若干段单调不上升的连续子序列(假设共$m$段),记其中第$i$段以$t_{l_{i}}$为开头,以$t_{r_{i}}$为结尾,且定义两个参数$R_{i}=nex_{l_{i}}$和$T_{i}=t_{R_{i}}$

当我们确定$R_{i-1}$和$T_{i-1}$后,来考虑$R_{i}$和$T_{i}$(特别的,$R_{0}=T_{0}=0$),分类讨论:

Case 1:$l_{i}<r_{i}$,此时必然有$T_{i}=c_{l_{i}}-1$,继续分类讨论——

Case 1.1:$t_{l_{i}}=t_{r_{i}}+1$,此时根据结论2,有$c_{l_{i}}=c_{l_{i}+1}=...=c_{r_{i}-1}=0$且$c_{r_{i}}=1$,那么不难得到$R_{i}=r_{i}$,此时来构造前面$(R_{i-1},l_{i})$之间1的情况

这些1的目的是保证$T_{i}$的值正确,更具体的,要在$(n-l_{i}+1,n-R_{i-1}]$中选择若干个不同的数(构造),使得其和为$T_{i}-T_{i-1}-(n-R_{i}+1)$(以下该值记作$\Delta_{i}$)

(关于这一类问题,为了不影响分类讨论,在分类讨论结束后再考虑)

Case 1.2:$t_{l_{i}}=t_{r_{i}}$,此时根据结论3,有两种情况,但注意到当第2种情况时,会有$\forall l_{i}\le k\le n,t_{k}\le t_{l_{i}}$,即若是此类情况其必要条件为$i=m$,那么继续分类讨论——

Case 1.2.1:$i<m$,此时根据结论3,有$c_{l_{i}}=c_{l_{i}+1}=...=c_{r_{i}}=0$(因为若是第2种情况,则显然$l_{i}$之后所有数都应该小于等于$t_{l_{i}}$),此时$R_{i}$即在$(r_{i},l_{i+1})$中任选

但当选出$R_{i}$后,我们需要保证可以在$(n-l_{i}+1,n-R_{i-1}]$中选择若干个不同的数,和为$\Delta_{i}$,且对于所有可行的$R_{i}$,可以贪心取其中最小的(即上面的范围扩大)

Case 1.2.2:$i=m$,此时不论$R_{i}$是在$(l_{i},r_{i})$中还是$(r_{i},n+1]$中,都可以令$\forall R_{i}<j\le n,c_{j}=0$(事实上这后面可以任意填,但这里就强制为0了)

$R_{i}$的选择范围是$[l_{i},n+1]$且$t_{R_{i}}\ne 0$,此时在其中找到任意一个合法(可以在$(n-l_{i}+1,n-R_{i}]$选择若干个数和为$\Delta_{i}$)即可

Case 2:$l_{i}=r_{i}$,此时$T_{i}=c_{l_{i}}$或$c_{l_{i}-1}$,且两种情况不像$R_{i}$在多种选择中可以贪心取最小,因此我们使用dp来解决,即用$f_{i,j}$表示$T_{i}=c_{l_{i}}-j$时最小的$R_{i}$,两类转移分类讨论——

Case 2.1:$f_{i,0}$的转移即与Case 1.1相同

Case 2.2:$f_{i,1}$的转移即与Case 1.2相同

(特别的,用$f_{i,j}=-1$表示该类不存在可行的$R_{i}$,那么对于**Case 1**中的情况只需要强制其为-1也可以以此法进行dp)

还需要考虑以下三个未解决的问题:

1.用$[l,r]$中选若干个数和为$x$

2.在$[l,r]$中选若干个数和在$[L,R]$中且尽量小

3.在$[l,r]$中选若干个数和在$S$中($S$为一个集合)

第3个问题由于仅有$i=m$时需要处理,因此可以$o(n)$暴力枚举$S$转换为第1个问题

对于第1个问题,考虑$[l,r]$所能表示的数,虽然并不一定是一个连续区间,但当选择的数个数确定时,一定是一个连续区间

更具体的,假设选择$t$个数($0\le t\le r-l+1$),所能表达的数为$[\sum_{i=l}^{l+t-1}i,\sum_{i=r-t+1}^{r}i]$,显然这个区间的左右端点具有单调性,即可以对$t$二分并判定是否包含

(关于这个区间的正确性,总是存在一个数使得其可以加1来构造即可)

当找到对应一个$t$后,若强制选$l$后,显然之后能覆盖的区间为$[\sum_{i=l}^{l+t-1}i,l+\sum_{i=r-t+2}^{r}i]$,类似地选$r$后能覆盖的区间为$[\sum_{i=l}^{l+t-2}i+r,\sum_{i=r-t+1}^{r}i]$,当$t\ge 2$时两者的并即为原区间

换言之,只需要不断选择$l$或$r$(要判断区间是否仍然包含$x$,总存在一个区间包含$x$)直至$t\le 1$即可

这样的复杂度是$o(r-l)$,在$f_{i,j}$转移时并不需要具体构造出方案,只需要在确定后构造即可,由于$r-l$即所有空隙长度和,总复杂度为$o(n)$

对于第2个问题,只是在转移时求,因此并不需要构造出方案,同样去二分找到第一个与$[L,R]$有公共点的$t$即可处理

综上,总复杂度为$o(n\log n)$,可以通过

  1 #include<bits/stdc++.h>
2 using namespace std;
3 #define N 200005
4 #define ll long long
5 vector<int>v;
6 int n,m,l[N],r[N],R[N],ans[N],f[N][2],fr[N][2];
7 ll t[N],T[N];
8 ll sum(int l,int r){
9 return 1LL*(l+r)*(r-l+1)/2;
10 }
11 ll find(int l,int r,ll L,ll R){
12 if (L>R)return -1;
13 int x=0,y=r-l+1;
14 while (x<y){
15 int mid=(x+y>>1);
16 if (sum(r-mid+1,r)>=L)y=mid;
17 else x=mid+1;
18 }
19 if ((sum(r-x+1,r)<L)||(R<sum(l,l+x-1)))return -1;
20 return max(sum(l,l+x-1),L);
21 }
22 void calc(int l,int r,ll k){
23 int x=0,y=r-l+1;
24 while (x<y){
25 int mid=(x+y>>1);
26 if (sum(r-mid+1,r)>=k)y=mid;
27 else x=mid+1;
28 }
29 if ((sum(r-x+1,r)<k)||(k<sum(l,l+x-1)))assert(0);
30 while (x>1){
31 if (k<=l+sum(r-x+2,r)){
32 k-=l;
33 ans[n-l+1]=1;
34 l++;
35 }
36 else{
37 k-=r;
38 ans[n-r+1]=1;
39 r--;
40 }
41 x--;
42 }
43 if (x==1)ans[n-k+1]=1;
44 }
45 int main(){
46 scanf("%d",&n);
47 for(int i=1;i<=n;i++)scanf("%lld",&t[i]);
48 for(int i=1;i<=n;i++)
49 if (t[i]>0)v.push_back(i);
50 for(int i=0;i<v.size();i++)
51 if ((!i)||(t[v[i]]>t[v[i-1]])){
52 if (m)r[m]=v[i-1];
53 l[++m]=v[i];
54 }
55 if (v.size())r[m]=v.back();
56 l[m+1]=n+1;
57 f[0][1]=-1;
58 for(int i=1;i<=m;i++)
59 for(int j=0;j<2;j++){
60 f[i][j]=-1;
61 if ((l[i]<r[i])&&(!j))continue;
62 ans[0]=ans[1]=-1;
63 for(int jj=0;jj<2;jj++){
64 if (f[i-1][jj]<0)continue;
65 ll delta=(t[l[i]]-j)-(t[l[i-1]]-jj);
66 if ((t[l[i]]>t[r[i]])||(l[i]==r[i])&&(!j)){
67 if (find(n-l[i]+2,n-f[i-1][jj],delta-(n-r[i]+1),delta-(n-r[i]+1))>=0)ans[jj]=r[i];
68 }
69 else{
70 if (i==m){
71 ans[jj]=-1;
72 for(int k=l[i];k<=n+1;k++)
73 if ((!t[k])&&(find(n-l[i]+2,n-f[i-1][jj],delta-(n-k+1),delta-(n-k+1))>=0)){
74 ans[jj]=k;
75 break;
76 }
77 continue;
78 }
79 ll s=find(n-l[i]+2,n-f[i-1][jj],delta-(n-r[i]),delta-(n-l[i+1]+2));
80 if (s>=0)ans[jj]=s-(delta-(n+1));
81 }
82 }
83 if ((ans[0]<0)&&(ans[1]<0))continue;
84 if ((ans[0]>=0)&&((ans[1]<0)||(ans[0]<ans[1])))fr[i][j]=0;
85 else fr[i][j]=1;
86 f[i][j]=ans[fr[i][j]];
87 }
88 int lst=-1;
89 if (f[m][0]>=0)lst=0;
90 if (f[m][1]>=0)lst=1;
91 memset(ans,0,sizeof(ans));
92 for(int i=m;i;i--){
93 R[i]=f[i][lst];
94 T[i]=t[l[i]]-lst;
95 lst=fr[i][lst];
96 if (R[i]<=n)ans[R[i]]=1;
97 }
98 for(int i=1;i<=m;i++)calc(n-l[i]+2,n-R[i-1],T[i]-T[i-1]-(n-R[i]+1));
99 for(int i=1;i<=n;i++)printf("%d",ans[i]);
100 }

[cf1349E]Slime and Hats的更多相关文章

  1. 更新lispbox中的ccl和slime版本

    首先C-x C-f然后输入~,找到.emacs文件,根据slime官方文档说明的添加如下代码到文件末尾,重启一下emacs,slime就编译好了,然后这段代码就可以删除.否则每次启动emacs就算不用 ...

  2. Wunder Fund Round 2016 (Div. 1 + Div. 2 combined) A. Slime Combining 水题

    A. Slime Combining 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=2768 Description Your frien ...

  3. 编写php拓展实例--slime项目(用户登录会话类)

      最近公司换了yaf框架,突然对用c实现php拓展感兴趣了,如果一个功能已经很稳定很成熟而且用的地方很多,那么我们就可以尝试用拓展实现(不一定每种情况都可以写成拓展),写成拓展后就不用每次用都包含一 ...

  4. Windows下安装Emacs+Sbcl+Slime

    前言 其实网上已经有很多类似的文章了,我也是按照上面的来做.在做的过程中会遇到几个很坑的地方,我自己也是折腾了好久才弄好.所以现在写出来希望能对大家有所帮助. 正文 下载和安装Emacs http:/ ...

  5. slime+sbcl for common lisp

    sudo apt-get install slime audo apt-get install sbcl ;;sbcl+slime for common lisp ;;sudo apt-get ins ...

  6. Common Lisp学习笔记(0):从SLIME开始 | 优哉·幽斋

    Common Lisp学习笔记(0):从SLIME开始 | 优哉·幽斋 Common Lisp学习笔记(0):从SLIME开始

  7. 在 Emacs 中如何退出 Slime Mode

    1.在 Slime 的 Buffer 中按逗号“,”: 2.在 Command 后输入:sayoonara 3.回车,确认. ================ 退出 SBCL 输入:(sb-ext:q ...

  8. [Codeforces Round #516][Codeforces 1063C/1064E. Dwarves, Hats and Extrasensory Abilities]

    题目链接:1063C - Dwarves, Hats and Extrasensory Abilities/1064E - Dwarves, Hats and Extrasensory Abiliti ...

  9. [CF1038D]Slime

    [CF1038D]Slime 题目大意: 有\(n(n\le5\times10^5)\)只史莱姆,每只史莱姆有一个分数\(w_i(|w_i|le10^9)\),每次一只史莱姆可以吞掉左边的或者右边的史 ...

随机推荐

  1. 在昨天夜黑风高的晚上,我偷了隔壁老王的Python入门课件,由浅入深堪称完美!

    隔壁老王是一个资深码农,就业教育事业的秃顶之才昨天我下楼打酱油,看他迎面走来,满目春光我好奇的问道:老王,有什么好事,隔壁小花叫你上门了吗?老王:秘密!!我心想:哎呦~不错啊半晚之时,连猫狗都睡着了, ...

  2. caffe.cpp解析

    来自链接:http://blog.csdn.net/u014114990/article/details/47747025 主要讲解:GetBrewFunction()函数定义如下,其返回BrewFu ...

  3. Oracle数据泵数据迁移

    1 表空间查询 1.1 检查用户与表空间对应情况 select username,default_tablespace from dba_users; 1.2    查看临时表空间 select ta ...

  4. The Data Way Vol.5|这里有一场资本与开源的 battle

    关于「The Data Way」 「The Data Way」是由 SphereEx 公司出品的一档播客节目.这里有开源.数据.技术的故事,同时我们关注开发者的工作日常,也讨论开发者的生活日常:我们聚 ...

  5. 题解 Yet Another Number Sequence

    题目传送门 Description 给出 \(n,k\) ,求出: \[\sum_{i=1}^{n} f_i·i^k \] 其中 \(f_i\) 表示斐波拉契第 \(i\) 项.\(n\le 10^{ ...

  6. 2020.5.17--牛客小白月赛25 F.疯狂的自我检索者

    F.疯狂的自我检索者 链接:https://ac.nowcoder.com/acm/contest/5600/F来源:牛客网 牛妹作为偶像乐队的主唱,对自己的知名度很关心.她平时最爱做的事就是去搜索引 ...

  7. 如何在印刷品中使用遵循SIL Open Font License协议的字体

    如何在印刷品中使用遵循SIL Open Font License协议的字体 昨天在知乎看到了一个问题,( 如何在设计中声明字体开源许可证? - 知乎 (zhihu.com),恰好最近在研究一些开源协议 ...

  8. JAVA复习总体大纲

    1 java基础. [1].变量--- 数据类型 变量名=值; 数据类型: 1.基本数据类型. byte[1字节] short[2字节] int[4字节] long[8字节] float[4字节] d ...

  9. 常用Java API:Math类

    求最值 最小值 Math.min(int a, int b) Math.min(float a, float b) Math.min(double a, doubleb) Math.min(long ...

  10. Oracle 19c 单机

    环境 vm虚拟机 双磁盘 操作系统 Oracle Linux 7.9 操作系统安装带图形 选择中文,注意不要新建用户 关闭防火墙 selinux 配置好IP 挂载系统盘镜像 修改主机名 配置hosts ...