Noip模拟7 2021.6.11
前言
考试时候der展了,T1kmp没特判(看来以后还是能hash就hash),T2搜索细节没注意,ans没清零,130飞到14。。。。
T1 匹配(hash/kmp)
这太水了,其实用个hash随便打打就过了,不知道当时想什么非要用个kmp看看那自己的毛片水平到不到位,kmp没写假,特判出问题了。。。。
Note:B加一个字符可能比A短,kmp扫描不到,所以要特判一下:
如果加的字符刚好与A的对应那一位相同,那么整个B就都是A的前缀,那么其x就是lengthB
1 #include<bits/stdc++.h>
2 using namespace std;
3 int T,nt[300005],la,lb,ans;
4 char ch[3],A[300005],B[300005];
5 inline void kmp(int len){
6 nt[1]=0;
7 for(int i=2,j=0;i<=len;i++){
8 while(j&&B[i]!=A[j+1]) j=nt[j];
9 if(B[i]==A[j+1]) nt[i]=++j;
10 else nt[i]=0;
11 }
12 }
13 namespace WSN{
14 inline int main(){
15 cin>>T;
16 while(T--){
17 memset(nt,0,sizeof(nt));
18 memset(B,0,sizeof(B));
19 cin>>la>>lb;
20 scanf("%s%s",A+1,ch+1);
21 for(int i=1;i<=lb;i++) B[i]=A[i];
22 B[++lb]=ch[1];
23 if(ch[1]==A[lb]){
24 printf("%d\n",lb);
25 continue;
26 }
27 kmp(lb);
28 printf("%d\n",nt[lb]);
29 }
30 return 0;
31 }
32 }
33 signed main(){return WSN::main();}
T2 回家
这题其实你看看就是个tarjan求割点的板子,然而苣蒻的小马只记得有向图缩点tarjan,割点的得用个什么儿子与父亲,剩下的全忘了,于是冲了一发信队,于是。。。
记得
数组和变量都清一次0,保证不会挂(不过时间说不定,但总比WA0强)
30分代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 inline int read(){
4 int x=0,f=1; char ch=getchar();
5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
7 return x*f;
8 }
9 int T,n,m,cnt,ind[800005],save[800005],ans,an[800005];
10 bool vis[800005];
11 struct SNOW{int from,to,next;}; SNOW e[400005<<1]; int r[400005<<1],tot;
12 inline void add(int x,int y){
13 if(x==y) return;
14 for(int i=r[x];i;i=e[i].next) if(e[i].to==y) return;
15 e[++tot]=(SNOW){x,y,r[x]}; r[x]=tot;
16 }
17 bool f;
18 inline bool dfs(int x){
19 // cout<<'x'<<x<<endl;
20 if(x==1) {f=1;return 1;}
21 vis[x]=1;
22 for(int i=r[x];i;i=e[i].next){
23 if(!vis[e[i].to]&&ind[e[i].to]!=0){
24 dfs(e[i].to);
25 }
26 }
27 return f==1? 1:0;
28 }
29 inline int check(int x){
30 for(int i=r[x];i;i=e[i].next)
31 ind[e[i].to]--;
32 ind[x]=0;
33 // cout<<x<<endl;
34 // for(int i=1;i<=n;i++) cout<<ind[i]<<" "; cout<<endl;
35 memset(vis,0,sizeof(vis)); f=0;
36 vis[x]=1;
37 if(dfs(n)) return 0;
38 else return 1;
39 }
40 namespace WSN{
41 inline int main(){
42 T=read();
43 while(T--){
44 memset(r,0,sizeof(r)); tot=0;
45 memset(an,0,sizeof(an)); ans=0;
46 memset(ind,0,sizeof(ind));
47 memset(save,0,sizeof(save));
48 n=read(),m=read();
49 for(int i=1;i<=m;i++){
50 int u=read(),v=read();
51 add(u,v); add(v,u);
52 ind[u]++; ind[v]++;
53 }
54 for(int i=1;i<=n;i++) save[i]=ind[i];
55 // for(int i=2;i<n;i++) if(ind[i]==2) cnt++;
56 // if(cnt==n-2&&ind[1]==1&&ind[n]==1){
57 // printf("%d\n",n-2);
58 // for(int i=2;i<n;i++) printf("%d ",i); putchar('\n');
59 // continue;
60 // }
61 // cout<<check(4)<<endl; continue;
62 for(int i=2;i<n;i++){
63 if(check(i)){ ans++; an[ans]=i; }
64 for(int i=1;i<=n;i++) ind[i]=save[i];
65 }
66 printf("%d\n",ans);
67 if(!ans){ printf("\n");continue; }
68 else{
69 for(int i=1;i<=ans;i++)
70 printf("%d ",an[i]);
71 putchar('\n');
72 }
73 }
74 return 0;
75 }
76 }
77 signed main(){return WSN::main();}
正解是在tarjan求割点上加一两步判断条件,有一种特别的情况,就是:
1
6 6
1 2
2 3
3 4
2 4
3 5
4 6
这组样例画出来就明白了,他1->6必经过3,4;而割点有2,3,4,所以只求割点是不行的
那么加一个vis数组用来记录跑深搜的时候是否经历过这个点,经历过并且符合割点条件的就是答案.
1 #include<bits/stdc++.h>
2 using namespace std;
3 inline int read(){
4 int x=0,f=1; char ch=getchar();
5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
7 return x*f;
8 }
9 int T,n,m,dfn[400005],low[400005],num,root,ans;
10 bool vis[400005],cut[400005];
11 struct SNOW{int to,next;}; SNOW e[800005]; int r[800005],tot;
12 inline void add(int x,int y){
13 if(x==y) return;
14 for(int i=r[x];i;i=e[i].next) if(e[i].to==y) return;
15 e[++tot]=(SNOW){y,r[x]}; r[x]=tot;
16 }
17 inline void tarjan(int x){
18 dfn[x]=low[x]=++num; int flag=0;
19 for(int i=r[x];i;i=e[i].next){
20 int y=e[i].to;
21 if(!dfn[y]){
22 tarjan(y);low[x]=min(low[x],low[y]);
23 if(vis[y]) vis[x]=true;
24 if(low[y]>=dfn[x]){
25 flag++;
26 if((x!=root||flag>1)&&vis[y]&&x!=n&&x!=1)
27 cut[x]=true,ans++;
28 }
29 }else low[x]=min(low[x],dfn[y]);
30 }
31 }
32 namespace WSN{
33 inline int main(){
34 T=read();
35 while(T--){
36 memset(r,0,sizeof(r));
37 memset(dfn,0,sizeof(dfn));
38 memset(low,0,sizeof(low));
39 memset(vis,0,sizeof(vis));
40 memset(cut,0,sizeof(cut));
41 tot=0; num=0; root=1; ans=0;
42 n=read(); m=read();
43 for(int i=1;i<=m;i++){
44 int u=read(),v=read();
45 add(u,v); add(v,u);
46 }
47 vis[n]=1; tarjan(1);
48 printf("%d\n",ans);
49 if(!ans){printf("\n"); continue;}
50 for(int i=2;i<n;i++) if(cut[i]) printf("%d ",i);
51 putchar('\n');
52 }
53 return 0;
54 }
55 }
56 signed main(){return WSN::main();}
T3 寿司(sushi)
思路一:
战神提供的nlogn做法。以每个R为断点记录前缀和B和后缀和B两个数组,可推出一个柿子:
然后将前面的l+r看成整体算出,后面的找规律:
破环成链时将字符串复制一倍,以原字符串长度向右每次移一位。
如果加入一个B,则l-r的值每个都对应-2;
如果加入一个R,则第一组差值取相反数并跑到最后,其余不变并上移一位。
例如:
/*12
BBRBBRBBBRRR
BRBBRBBBRRRB
RBBRBBBRRRBB
BBRBBBRRRBBR
BRBBBRRRBBRB
RBBBRRRBBRBB
BBBRRRBBRBBR
BBRRRBBRBBRB
BRRRBBRBBRBB
RRRBBRBBRBBB
RRBBRBBRBBBR
RBBRBBRBBBRR
2 5|4 3|7 0|7 0|7 0|
1 6|3 4|6 1|6 1|6 1|
0 7|2 5|5 2|5 2|5 2|
2 5|5 2|5 2|5 2|7 0|
1 6|4 3|4 3|4 3|6 1|
0 7|3 4|3 4|3 4|5 2|
3 4|3 4|3 4|5 2|7 0|
2 5|2 5|2 5|4 3|6 1|
1 6|1 6|1 6|3 4|5 2|
0 7|0 7|0 7|2 5|4 3|
0 7|0 7|2 5|4 3|7 0|
0 7|2 5|4 3|7 0|7 0|
一组|中间的的每两个为断点左右绝对值*/
1 #include<bits/stdc++.h>
2 using namespace std;
3 inline int read(){
4 int x=0,f=1; char ch=getchar();
5 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
6 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
7 return x*f;
8 }
9 int T,numB,ans,tot,frt[1000005],bak[1000005];
10 char s[1000005];
11 namespace WSN{
12 inline int main(){
13 T=read();
14 while(T--){
15 memset(frt,0,sizeof(frt)); tot=1;
16 memset(bak,0,sizeof(bak)); ans=0;
17 numB=0;
18 scanf("%s",s+1);
19 int len=strlen(s+1);
20 for(int i=1;i<=len;i++){
21 if(s[i]=='B')
22 numB++,frt[tot]++;
23 if(s[i]=='R') tot++;
24 }
25 for(int i=1;i<=tot;i++)
26 frt[i]+=frt[i-1], bak[i]=numB-frt[i];
27 for(int i=1;i<tot;i++) cout<<frt[i]<<" "<<bak[i]<<"|";
28 putchar('\n');
29 }
30 return 0;
31 }
32 }
33 signed main(){return WSN::main();}
这样的话还要用大根堆维护,求出每组数差值的变化量以便统计最大的减数(也就是绝对值那一坨)
就在我还在苦思如何使用大根堆时,正解的n复杂度出现了
B哥大定理(BBT)
通过巨量的打表发现规律:只求复制后卡的区间的每个中点求出R向两侧移动的步数的最小值便是最优值。
这样通过维护每一个点的前缀B个数,后缀B个数,前缀R个数,R向左移的步数及向右移的步数,就可O(1)出解
再每中情况去中点扫一遍就行:
1 #include<bits/stdc++.h>
2 #define int long long
3 using namespace std;
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(); }
8 return x*f;
9 }
10 const int NN=2000005;
11 int T,ans,tot,lb[NN],rb[NN],lr[NN],stl[NN],str[NN],numB;
12 char s[NN];
13 inline int qiu(int l,int mid,int r){
14 return stl[mid]-stl[l-1]-lb[l-1]*(lr[mid]-lr[l-1])+str[mid+1]-str[r+1]-rb[r+1]*(lr[r]-lr[mid]);
15 }
16 namespace WSN{
17 inline int main(){
18 T=read();
19 while(T--){
20 ans=0x3ffffffffffff;
21 scanf("%s",s+1);
22 int len=strlen(s+1);
23 for(int i=1;i<=len;i++) s[i+len]=s[i];
24 len*=2;
25 for(int i=1;i<=len;i++){
26 lb[i]=lb[i-1];
27 lr[i]=lr[i-1];
28 stl[i]=stl[i-1];
29 if(s[i]=='B') lb[i]++;
30 else lr[i]++, stl[i]+=lb[i];
31 }
32 for(int i=len;i>=1;i--){
33 rb[i]=rb[i+1];
34 str[i]=str[i+1];
35 if(s[i]=='B') rb[i]++;
36 else str[i]+=rb[i];
37 }
38 int n=len/2;
39 for(int i=1;i<=n;i++){
40 int mid=(i+i+n-1)>>1;
41 ans=min(ans,qiu(i,mid,i+n));
42 }
43 printf("%lld\n",ans);
44 }
45 return 0;
46 }
47 }
48 signed main(){return WSN::main();}
END
这次考试总觉得应拿到130或稍微第一点,可是呢,失误太多了,以后看到题能用必对的方法就不用拿不准的(总之hash比对)
Noip模拟7 2021.6.11的更多相关文章
- Noip模拟74 2021.10.11
T1 自然数 考场上当我发现我的做法可能要打线段树的时候,以为自己百分之百是考虑麻烦了 但还是打了,还过掉了所有的样例,于是十分自信的就交了 正解还真是线段树,真就第一题数据结构 但是包括自己造的小样 ...
- Noip模拟36 2021.8.11
刚题的习惯还是改不了,怎么办??? T1 Dove打扑克 考场上打的动态开点线段树+并查集,考后发现自己像一个傻子,并查集就行.. 这几天恶补数据结构疯了 用树状数组维护后缀和,$siz_i$表示编号 ...
- Noip模拟50 2021.9.10
已经好长时间没有考试不挂分的良好体验了... T1 第零题 开场数据结构,真爽 对于这道题首先要理解对于一条链从上向下和从下向上走复活次数相等 (这可能需要晚上躺在被窝里面脑摸几种情况的样例) 然后就 ...
- 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$的直线, 然后题意转化为移动最少的步数使得所有点都在某一个点的两条直线上 二分出直线的高度,判断条件是尽量让这条直线上部 ...
随机推荐
- 详解C3P0(数据库连接池)
详解C3P0(数据库连接池) 快速索引 一.基本定义 二.使用C3P0(数据库连接池)的必要性 1.JDBC传统模式开发存在的主要问题 三.数据库连接池的详细说明 四.使用连接池的明显优势 1.资源的 ...
- go中导入包的几种方式
标准方式: import ( "fmt" )使用:fmt.Println() 点(.)方式 import ( . "fmt" ) 使用时候,可以胜率fmt前缀P ...
- Windows phone 8 触发器使用小结
引用空间: xmlns:ec="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expres ...
- 解决国内npm安装太慢的方法,又不能FQ情况下,使用淘宝镜像教程
安装npm及cnpm(Windows) [工具官网] 因为国内上网下载组件太慢,淘宝给我们提供了镜像源,,但是我不是建意FQ上网.条件有限的可以使用下面的方法安装CNPM,原文转自网络,正好自己需要也 ...
- vue报错 Uncaught TypeError: Cannot read property of null
有可能是点击a标签,但是a标签有click事件,未阻止默认事件导致报错,开始都看不出来是什么错误
- azkaban3.90.0部署
1.下载这个网友提供的编译包,自己编的老出错,没弄了 https://blog.csdn.net/logincheck/article/details/110119987 2.将 解压到 /opt/m ...
- ecshop商品自定义销量(虚拟销量)实现方法
1.在sq执行语句 ALTER TABLE `ecs_goods` ADD `sales_volume_base` INT( 10 ) UNSIGNED NOT NULL DEFAULT '0' ...
- DEDE判断当前是否有下级栏目,有就显示所有下级栏目,没有就显示同级栏目!
{dede:channel name='type' runphp='yes' if(reid == "0") @me = "son";else @me = &q ...
- Pycharm 使用问题一览
1. I'm not sure if it is the problem of Pycharm or any other IDE. 需要从本地文件中导入文件,但总是出现波浪线,按ctril点进去发现是 ...
- Android Kotlin协程入门
Android官方推荐使用协程来处理异步问题.以下是协程的特点: 轻量:单个线程上可运行多个协程.协程支持挂起,不会使正在运行协程的线程阻塞.挂起比阻塞节省内存,且支持多个并行操作. 内存泄漏更少:使 ...