Noip模拟49 2021.9.7
T1 reverse
又一道板子打假的挂分题,直接挂到倒二。。
考场上思路神奇,居然想到用$bfs$建边然后跑最短路,
其实当时也想到了直接$bfs$,但是不知道为啥觉得$dij$屌就没直接打$bfs$。。。
最可怕的是$dji$没打对,以后可能要早操背板子了。。。
然后其实这题能卡过,因为$k$都特别小。


1 #include<bits/stdc++.h>
2 using namespace std;
3 namespace AE86{
4 inline int read(){
5 int x=0,f=1;char ch=getchar();
6 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
7 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
8 }inline void write(int x,char opt='\n'){
9 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
10 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
11 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
12 }using namespace AE86;
13
14 inline int max(int a,int b){return a>b?a:b;}
15 inline int min(int a,int b){return a<b?a:b;}
16
17 int n,k,m,s,ans[100005],pos,wei,l,r;
18 bool vis[100005];
19 double mid;
20 int q[100005],h=0,t=0;
21 namespace WSN{
22 inline short main(){
23 // freopen("reverse3.in","r",stdin);
24 // freopen("bl.out","w",stdout);
25 n=read(); k=read(); m=read(); s=read();
26 for(register int i=1;i<=n;++i) ans[i]=-1;
27 for(register int i=1,jz;i<=m;++i)
28 jz=read(),vis[jz]=1,ans[jz]=-1;
29 q[++t]=s; ans[s]=0; vis[s]=1;
30 while(h<=t){
31 pos=q[h++];
32 l=max(1,pos-k+1); r=min(pos,n-k+1);
33 for(register int i=l;i<=r;++i){
34 wei=i+(k-(pos-i+1));
35 if(!vis[wei]){
36 ans[wei]=ans[pos]+1;
37 vis[wei]=1;
38 q[++t]=wei;
39 }
40 }
41 }
42 for(register int i=1;i<=n;++i)
43 write(ans[i],' ');
44 return 0;
45 }
46 }
47 signed main(){return WSN::main();}
卡常暴力
然后正解能优化到$O(n)$,就是使用一个链表,
发现每个$1$每次挪动的位置奇偶性都是一样的,那么初始化链表为$nxt_i=i+2$
然后$bfs$每次循环的时候直接找能跳到的位置并把链表指针指向循环最后一个元素。


1 #include<bits/stdc++.h>
2 using namespace std;
3 namespace AE86{
4 inline int read(){
5 int x=0,f=1;char ch=getchar();
6 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
7 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
8 }inline void write(int x,char opt='\n'){
9 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
10 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
11 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
12 }using namespace AE86;
13
14 inline int max(int a,int b){return a>b?a:b;}
15 inline int min(int a,int b){return a<b?a:b;}
16
17 int n,k,m,s,ans[100005],pos,l,r,nxt[100005],wei,nt;
18 bool vis[100005];
19 int q[100005],h=0,t=0;
20 namespace WSN{
21 inline short main(){
22 n=read(); k=read(); m=read(); s=read();
23 for(register int i=1;i<=n;++i) ans[i]=-1;
24 for(register int i=1;i<=m;++i) vis[read()]=1;
25 q[++t]=s; ans[s]=0; vis[s]=1;
26 for(int i=1;i<=n;i++) nxt[i]=i+2;
27 while(h<=t){
28 pos=q[h++]; l=max(1,pos-k+1); r=min(pos,n-k+1);
29 wei=l*2+k-pos-1;
30 while(wei<=r*2+k-pos-1){
31 nt=nxt[wei]; nxt[wei]=nxt[r*2+k-pos-1];
32 if(!vis[wei]) ans[wei]=ans[pos]+1,vis[wei]=1,q[++t]=wei;
33 wei=nt;
34 }
35 }
36 for(register int i=1;i<=n;++i) write(ans[i],' ');
37 return 0;
38 }
39 }
40 signed main(){return WSN::main();}
O(n)
T2 Silhouette
首先可以看出俯视图是$min(a_i,b_j)$,就是说每个点叠最多只有那么多块。
然后发现对于给出数组排序前后计算的答案一样,证明见 这里
然后这样我们对于每一段$S$相同的区域分别处理,这一块区域之可能是矩形或者"L"形
为了不让每一列相互影响,我们假设$f_i$表示至少有$i$行没有一个块的高度等于$S$,那么对于$f_0$可以容斥出来
考虑$f_i$如何计算:
$f_i=C_{a}^{i}*(S^i*((S+1)^{a-i}-S^{a-i}))^b$
这个柿子是对于第一块(也就是$S$是矩形)的情况。
(好吧这是粘别人的)
从$a$行里面选择$i$行不合法(就是没有一个块的高度等于$S$), $C_{a}^{i}$
然后对于每一列里面有$i$行只能选择$[0~S-1]$中的数,$S^i$
剩下的$a-i$行随便选,然后减去那一行不是$S$的情况 $(S+1)^{a-i}-S^{a-i}$
共有$b$列并且互不影响。
然后看普遍情况
有以上三种,其中后两种都可以按特殊情况告搞
考虑"L"形:分开搞
对于矩形的两种情况,无非就是没有了那一部分,可以认为举行是一种特殊的L行。
为方便,我们不妨将L行区域按如下图方式标号:
$f_i=C_a^i*(S^i*((S+1)^{a+c-i}-S^{a+c-i}))^b*(S^i*(S+1)^{a-i})^d$
因为上图中红色区域已经处理完毕,
所以对于蓝色区域,其已经满足行,而没有满足列,
对于绿色区域,其已经满足列,没有满足行
关于组合数,因为前面的$c$已经处理过,是合法的,所以我们只考虑在$a$行中选择不和法行,处理$1$区域与特殊部分同理。
然后处理绿色的$2$部分,这一部分列已经满足,所以关于特殊部分里面的减去一个$S^{a-i}$来保证合法就没有必要了
于是就直接$*(S^i*(S+1)^{a-i})^d$就可以了
这些东西都懂了代码就没什么了,很好理解。


1 #include<bits/stdc++.h>
2 #define int long long
3 using namespace std;
4 namespace AE86{
5 inline int read(){
6 int x=0,f=1;char ch=getchar();
7 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
8 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
9 }inline void write(int x,char opt='\n'){
10 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14
15 const int NN=1e5+5,mod=1e9+7;
16 int n,a[NN],b[NN],m[NN<<1],has,ans=1;
17 int h[NN],v[NN];
18 inline int qmo(int a,int b){int ans=1,c=mod;a%=c;while(b){if(b&1)ans=ans*a%c;b>>=1;a=a*a%c;}return ans;}
19 inline void pre(){
20 h[0]=h[1]=1; v[0]=v[1]=1;
21 for(int i=2;i<=100000;i++) h[i]=h[i-1]*i%mod;
22 v[100000]=qmo(h[100000],mod-2);
23 for(int i=99999;i>=2;i--) v[i]=v[i+1]*(i+1)%mod;
24 }
25 inline int C(int n,int m){
26 if(n<m||n<0||m<0) return 0;
27 return h[n]*v[n-m]%mod*v[m]%mod;
28 }
29
30 inline int calc(int a,int b,int c,int d,int s,int ans=0){
31 for(int i=0;i<=a;i++){
32 int res=C(a,i)*qmo(qmo(s,i)*((qmo(s+1,a+c-i)-qmo(s,a+c-i)+mod)%mod)%mod,b)%mod*qmo(qmo(s,i)*qmo(s+1,a-i)%mod,d)%mod;
33 if(i&1) ans=(ans-res+mod)%mod;else ans=(ans+res)%mod;
34 } return ans;
35 }
36
37 namespace WSN{
38 inline short main(){
39 n=read(); pre();
40 for(int i=1;i<=n;i++) a[i]=read(),m[i]=a[i];
41 for(int i=1;i<=n;i++) b[i]=read(),m[i+n]=b[i];
42 sort(a+1,a+n+1); sort(b+1,b+n+1);
43 if(a[n]!=b[n]) return puts("0"),0;
44 sort(m+1,m+2*n+1); has=unique(m+1,m+2*n+1)-m-1;
45 int pa=n+1,pb=n+1,na=n,nb=n;
46 for(int i=has;i;i--){
47 while(a[na-1]==m[i]&&na-1) --na;
48 while(b[nb-1]==m[i]&&nb-1) --nb;
49 ans=ans*calc(pa-na,pb-nb,n-pa+1,n-pb+1,m[i])%mod;
50 pa=na; pb=nb;
51 } write(ans);
52 return 0;
53 }
54 }
55 signed main(){return WSN::main();}
T3 seat
据说$dp$很玄学,不大会。。。。
只知道$skyh$大神倾情压行代码加注释。
$UPD 2021.9.9$
好了,差不多会了(只能说是一知半解)
代码里面的注释非常多了,直接看着那个理解就好了。。。


1 #include<bits/stdc++.h>
2 using namespace std;
3 namespace AE86{
4 inline int read(){
5 int x=0,f=1;char ch=getchar();
6 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
7 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
8 }inline void write(int x,char opt='\n'){
9 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
10 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
11 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
12 }using namespace AE86;
13
14 const int NN=1030;
15 int n,mod,inv[NN],vis[NN];
16 int cnt[NN];//记录对于距离为i的区间有几个,也就是 记录分出的log层,每一层区间的个数
17 int pos[NN];//每个人对应的位置
18 int odd[NN];//偶数长度大小的区间的个数,也是在这一层的人数
19 int ans[NN][NN];//记录答案
20 int f[NN][NN],g[NN][NN];
21
22 inline int qmo(int a,int b){int ans=1,c=mod; a%=c;while(b){if(b&1) ans=ans*a%c;b>>=1; a=a*a%c;} return ans;}
23
24 namespace WSN{
25 inline short main(){
26 n=read(); mod=read(); vis[0]=vis[n+1]=1;
27 for(int i=1;i<=n;i++) inv[i]=qmo(i,mod-2);
28 for(int i=1;i<=n;i++){
29 int L=0,R=0,l=0,maxn=0;
30 while(l<=n){//注意l表示区间左端点-1,r表示右端点+1
31 int r=l+1;
32 while(!vis[r])++r;
33 if(r-l>R-L) R=r,L=l;
34 l=r;
35 }
36 ++cnt[maxn=R-L>>1]; //maxn记录区间中的那个人与两端的人的距离
37 if(R-L&1) ++odd[maxn];//R-L为奇数,表示区间长度为偶数
38 pos[i]=L+maxn; vis[L+maxn]=1;//标记有了座位的人的位置
39 }
40 int sum=n;
41 for(int i=1;i<=n;i++) if(cnt[i]){
42 int l=sum-cnt[i]+1,r=sum;
43 if(i==1)//叶子节点特殊处理,题解上说的
44 for(int j=l;j<=r;j++) for(int k=l;k<=r;k++)
45 ans[j][pos[k]]=inv[cnt[i]];
46 else{
47 for(int j=0;j<=cnt[i];j++) for(int k=0;k<=odd[i];k++) f[j][k]=0;
48 f[0][odd[i]]=1;
49 int last=l+odd[i]-1;//默认前面的区间是偶区间的最后一个人
50 //就是最后一个在偶区间里面的人
51 for(int j=1;j<=cnt[i];j++){
52 int oddw=0,evew=0;
53 for(int k=0;k<=odd[i];k++) if(f[j-1][k]){
54 int mu=(cnt[i]-(j-1))+k,w=0;
55 if(k){//如果有偶数剩余
56 w=f[j-1][k]*k%mod*2%mod*inv[mu]%mod;//w辅助转移,k表示偶数的区间个数,所以转移位置都是2×k
57 (oddw+=w*inv[odd[i]*2])%=mod;
58 (f[j][k-1]+=w)%=mod;
59 }
60 if(cnt[i]-odd[i]){//如果有奇数剩余
61 w=f[j-1][k]*(mu-k*2+mod)%mod*inv[mu]%mod;//减去偶数转移点
62 (evew+=w*inv[(cnt[i]+odd[i])-odd[i]*2])%=mod;//注意总转移点个数为cnt[i]+odd[i]
63 (f[j][k]+=w)%=mod;//注意k不-1,因为转移的是奇数
64 }
65 }
66 for(int k=l;k<=last;k++) (ans[l+j-1][pos[k]]+=oddw)%=mod,(ans[l+j-1][pos[k]+1]+=oddw)%=mod;
67 //偶数可以选择的两个位置分别是pos[k],pos[k]+1,以此累加答案
68 for(int k=last+1;k<=r;k++) (ans[l+j-1][pos[k]]+=evew)%=mod;
69 //奇数同理
70 }
71 for(int j=l;j<=last;j++){
72 int L=pos[j]-i+1,R=pos[j]+i;//j这个人所在区间的左右端点
73 for(int k=L;k<=R;k++) if(pos[j]!=k)//枚举区间内每个位置
74 for(int u=r+1;u<=n;u++){
75 int s=(k<pos[j]?k+i+1:k-i);//找到等对称点
76 //关于等对称点,我们看一下下面我手玩的样例
77 /*
78 |___|___|___|___|___|
79 7 8 9 10 11 12
80 这个样例的pos[j]为9,(因为不知道是哪个人,pos没有写下标),距离i为3,
81 L=7 ,R=12
82 这样发现,如果j这个人选择在9,那么区间划分成7,8和10,11,12
83 如果这个人在10,那么区间划分成7,8,9和11,12
84 这样{
85 7->11
86 8->12
87 10->7
88 11->8
89 12->9
90 }
91 按这样进行编码就会是以上的那样。
92 */
93 int w=ans[u][k]*inv[2]%mod;//后一个人在位置k的概率除以2
94 (g[u][k]+=w)%=mod; (g[u][s]+=w)%=mod; //然后把w均分到这两种等效的情况上
95 //此时会出现两个位置可供选择
96 //但无论选择哪一个,都会将区间划分成长度为n/2和n/2-1的两段。
97 //因此这两种选择具有对称性,我们只需要假定选择其中的一个,算出这种情况下之后的层的答案,即可对称地推出另一种情况下的答案。
98 //以上的均分找对称点就可以解决如上题解所说的问题
99 }
100 for(int k=L;k<=R;k++) for(int u=r+1;u<=n;u++) ans[u][k]=g[u][k],g[u][k]=0;
101 }
102 }
103 sum-=cnt[i];//减掉处理完的人数;
104 }
105 for(int i=1;i<=n;i++){
106 for(int j=1;j<=n;j++)
107 write(ans[i][j],' ');
108 puts("");
109 }
110 return 0;
111 }
112 }
113 signed main(){return WSN::main();}
超级详细的注释代码
Noip模拟49 2021.9.7的更多相关文章
- 2021.9.7考试总结[NOIP模拟49]
T1 Reverse $BFS$暴力$O(n^2)$ 过程中重复枚举了很多点,考虑用链表记录当前点后面可到达的第一个未更新点. 搜索时枚举翻转子串的左端点,之后便可以算出翻转后$1$的位置. $cod ...
- Noip模拟70 2021.10.6
T1 暴雨 放在第一道的神仙题,不同的做法,吊人有的都在用线段树维护$set$预处理 我是直接$dp$的,可能代码的复杂度比那种的稍微小一点 设$f[i][j][p][0/1]$表示考虑了前$i$列, ...
- Noip模拟76 2021.10.14
T1 洛希极限 上来一道大数据结构或者单调队列优化$dp$ 真就没分析出来正解复杂度 正解复杂度$O(q+nm)$,但是据说我的复杂度是假的 考虑一个点转移最优情况是从它上面的一个反$L$形转移过来 ...
- Noip模拟69 2021.10.5
考场拼命$yy$高精度结果没学好$for$循环痛失$50pts$,当场枯死 以后一定打对拍,要不考后会... T1 石子游戏 首先要知道典型的$NIM$博弈,就是说如果所有堆石子个数的异或和为$0$则 ...
- Noip模拟63 2021.9.27(考场惊现无限之环)
T1 电压机制 把题目转化为找那些边只被奇数环包含. 这样的话直接$dfs$生成一棵树,给每个点附上一个深度,根据其他的非树边都是返祖边 可以算出环内边的数量$dep[x]-dep[y]+1$,然后判 ...
- Noip模拟61 2021.9.25
T1 交通 考场上想了一个$NPC$.应该吧,是要求出图里面的所有可行的不重复欧拉路 无数种做法都无法解出,时间也都耗在这个上面的,于是就考的挺惨的 以后要是觉得当前思路不可做,就试着换一换思路,千万 ...
- Noip模拟59 2021.9.22
新机房首模拟变倒数 T1 柱状图 关于每一个点可以做出两条斜率分别为$1,-1$的直线, 然后题意转化为移动最少的步数使得所有点都在某一个点的两条直线上 二分出直线的高度,判断条件是尽量让这条直线上部 ...
- Noip模拟52 2021.9.13
T1 异或 比较稳的切掉 观察数据范围,无法线性筛啥的,根号复杂度也会死,于是只能考虑$log$级 然后打表 发现当$n$为$2^i$时的答案是一个可递归数列: $1,3,7,15,31,63,127 ...
- Noip模拟51 2021.9.12
T1 茅山道术 考场上卡在了一个恶心的地方, 当时以为每次施法都会产生新的可以施法的区间,然后想都没细想, 认为不可做,甚至$dfs$也无法打,考后一问发现是自己想多了.. 新产生的区间对答案根本没有 ...
随机推荐
- C# List集合类常用操作:三、查找
List集合查询数据 List<Employees> employees = new List<Employees>(); employees.Add(new Employee ...
- project read error(项目读取错误)
maven的pom文件出现project read error 1,打开电脑cmd操作界面,在cmd界面找到打开出错项目的文件夹; 比如我的项目文件夹在D:\>eclipse-jee-file\ ...
- pyhton锁机制,进程池
第一,进程锁,本来进程是各自的,本不要加锁,但是在屏幕上输出打印时为了防止混乱,在进程模块有一个锁函数,使用如下,需要说明是在py3以上版本没 有出现在过屏幕输出混乱,可以不加,这方法不重要,但是作为 ...
- 机器学习——EM算法
1 数学基础 在实际中,最小化的函数有几个极值,所以最优化算法得出的极值不确实是否为全局的极值,对于一些特殊的函数,凸函数与凹函数,任何局部极值也是全局极致,因此如果目标函数是凸的或凹的,那么优化算法 ...
- # Zombie Gunship Survival(僵尸炮艇生存)GG修改器修改教程
Zombie Gunship Survival(僵尸炮艇生存)GG修改器修改教程 1.修改伤害,打击范围,武器冷却时间,子弹容量 测试手机机型:华为畅享7 系统版本:Android7.0 是否ROOT ...
- PHP中命名空间是怎样的存在(一)?
命名空间其实早在PHP5.3就已经出现了.不过大部分同学可能在各种框架的使用中才会接触到命名空间的内容,当然,现代化的开发也都离不开这些能够快速产出的框架.这次我们不从框架的角度,仅从简单的代码角度来 ...
- TP5 windows中执行定时任务
1 首先先写个自定义命令文件 比如 Test 2 在网站根目录下建立文件 crond.bat ,内容:(把你在cmd上操作流程写一遍) D: cd workspace\wamp\tp5 D:\PHPW ...
- [原创]OpenEuler20.03安装配置PostgreSQL13.4详细图文版
OpenEuler安装配置PostgreSQL 编写时间:2021年9月18日 作者:liupp 邮箱:liupp@88.com 序号 更新内容 更新日期 更新人 1 完成第一至三章内容编辑: 202 ...
- 4.深入TiDB:执行计划执行过程详解
本文基于 TiDB release-5.1进行分析,需要用到 Go 1.16以后的版本 转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/ ...
- cmake入门:01 构建一个简单的可执行程序
一.目录结构 CMakeLists.txt:cmake 工程入口文件,包含当前目录下的工程组织信息.cmake 指令根据此文件生成相应的 MakeFile 文件. Hello.c: 源代码文件 bui ...