【NOIP模拟_54测试】【并查集】【二进制】【搜索】【区间序列类】

第一题 Mushroom的序列 大意:

  给一个序列,求一段连续最长区间满足:最多改变一个数,使得区间是严格的上升子序列。

解:

  直接扫描一遍,记一个最长上升子序列编号。然后从每一个编号为1 的点来判断是否可以将两个序列合并,有两种情况,讨论需要注意多种子情况。。。我可能想的比较复杂,所以第一遍写的时候少考虑了一些相等的情况,就WA 了一个点。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 100005
 6 using namespace std;
 7 int n,num[maxn],f[maxn],last=1,l[maxn],pre[maxn],ans;
 8 int main()
 9 {
10     freopen("seq.in","r",stdin);
11     freopen("seq.out","w",stdout);
12     cin>>n;
13     for (int i=1;i<=n;i++)
14     {
15         scanf("%d",&num[i]);
16         if (i==1) f[i]=1;
17         else {
18             if (num[i]>num[i-1]) f[i]=f[i-1]+1;
19             else {
20                 f[i]=1;pre[i]=last;
21                 l[last]=f[i-1];last=i;
22             }
23         }
24     }
25     l[last]=f[n];
26     ans=1;
27     for (int i=1;i<=n;i++)
28     if (l[i]){
29         ans=max(l[i],ans);
30         if (i!=1&&num[i+1]<num[i-1]){
31             if (num[i]>num[i-2]+1) ans=max(ans,l[pre[i]]+l[i]);
32             else ans=max(ans,max(l[pre[i]]+1,l[i]+1));
33         }
34         else if (i!=1&&num[i+1]>=num[i-1]){
35             if (num[i+1]>num[i-1]+1) ans=max(ans,l[pre[i]]+l[i]);
36             else if (num[i]>num[i-2]+1) ans=max(ans,l[pre[i]]+l[i]);
37             else ans=max(ans,max(l[pre[i]]+1,l[i]+1));
38         }
39         else ans=max(ans,max(l[pre[i]]+1,l[i]+1));
40     }
41     if (ans>n) ans=n;
42     cout<<ans;
43     return 0;
44 }

第二题 Mushroom的区间 大意:

  一个初始全部为0长度为n的序列,给m个区间,对于区间[l,r]的处理为翻转区间内的数 1->0, 0->1,问这m个区间操作能得到多少个不同的序列(即可以只进行一个区间操作也可以对序列进行多个区间翻转操作得到新序列)。如:当n=3,m=3,区间依次为:1 1 ,2 2 , 3 3 的时候有8种不同的序列。

 解:

  我们可以通过画图推导出如果没有判重,那么新序列数与n没有关系,=2^m。但是需要判重,有两种情况。

  第一种:(横线代表区间)

              1

     2

           3

               4

  因为 1 区间的翻转等效于 2+3+4 区间的翻转,所以这个情况要排除。同时1+2+3+4也是重复的排除,那么ans不乘2。

 第二种:

            1

         2

            3

        4   
  因为2+3+4区间翻转等于翻转 1区间,因为2、3、4它们的重合部分翻转抵消了。

  所以,如果把一个区间的 L ,R 当做一条边的端点,在链上连边(双向),如果回到已经到过的点,说明是重复的,那么这样我们可以用并查集来表示,用父亲节点判断是不是走过的就可以了。比较巧妙,值得学习。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define maxn 100005
 6 #define P 1000000007
 7 using namespace std;
 8 int n,m,fa[maxn],ans=1;//***初值
 9 int find(int x)
10 {
11     if (x==fa[x]) return x;
12     else  return fa[x]=find(fa[x]);//return
13 }
14 int main()
15 {
16     freopen("seg.in","r",stdin);
17     freopen("seg.out","w",stdout);
18     cin>>n>>m;
19     for (int i=1;i<=n+1;i++)// n+1
20        fa[i]=i;
21     for (int i=1;i<=m;i++)
22     {
23         int x,y;
24         scanf("%d%d",&x,&y);
25         int a=find(x);
26         int b=find(y+1);//平移右边界
27         if (a!=b){
28             ans=(ans*2)%P;
29             fa[a]=b;
30         }
31     }
32     cout<<ans;
33     return 0;
34 }

第三题 来自风平浪静的明天 大意:

  好吧,太扯,不想写。但是其实他的题目更扯。。。

【题目描述】
冬眠了五年,光终于从梦中醒来。
千咲、要,大家都在。
隐约记得“昨天”的海船祭,爱花意外成为贡女,沉入海底。
海面冰封,却有丝丝暖流在冰面之下涌动。
此时,爱花沉睡在祭海女神的墓地。她的胞衣在一点点脱落,化作一簇簇暖流,夹杂着她的感情,向海面上涌去。
爱花,你在哪里?
五年之后,纺已经成为海洋学研究科的大学生。
在纺的帮助下,光得知了海面下海流的情况。
纺告诉光,暖流一旦产生,就会不断地向四周扩散,直到遇到海中的岩石。
红腹海牛,快告诉光,爱花在哪里。
纺帮你绘制了一张海流情况图,长度为N,宽度为M。
海很大,一边有沙滩,一边一望无际,但长度和宽度都不会超过300。沙滩是金黄色的,所以用Y表示。海是蓝色的,所以用B表示。暖流很暖和,所以用H表示
海中有大大小小的石头。石头很危险,所以用X表示
光相信自己一定能找到爱花(爱花的位置只有一种可能)
【输入格式】
第一行包括两个整数N,M。
接下来N行,每行M个字符。
【输出格式】
仅一行,表示爱花的位置(如果你无能为力,请输出 -1 ,只要你尽力,光不会责怪你)
【样例输入】
5 5
YYYHB
YYHHH
YHHXB
BBHBB
BBBBB
【样例输出】
2 3
【数据范围】
对于30%的数据,n,m<=10
对于70%的数据,n,m<=100
对于100%的数据,n,m<=300
【样例解释】
在(2,3)出现第一个H后,经过3s后,出现样例输入的地图。
P.S. Mushroom拜托他GF出的这题= =

解:

  考试的时候想的是直接枚举每一个H ,然后判断它是不是。判断的时候我用的dfs,记一个层数,对于有两个数组记录每一个层数有没有H,有没有B,如果存在有一层同时有H,同时有B,那这个就不是ans。但是有一个致命的缺陷就是,有可能对于一个非ans的点,从它开始遍历刚好可以把所有点遍历完,而且没有访问到B,这个时候,我就输出了,然后WA 了9个点。。、所以可以用BFS 解决这个问题。但有可能会超时一个点,再改成手写队列就可以了。

  其实可以这样想:找出那一片H的边界,即与B相连 的 H,把它 “变成B” ,然后继续更新新的边界H,以此类推,最后一个就是中心。用一个sco数组来记录,初值是-1,B是0,先用B来更新它旁边的H为1,然后再更新下一个边界H 的值为2,最后最大的那个sco值为中心。但这样也有问题,如果有一边全是不能走的X,Y ,那么有可能在推的时候会把一个夹在这X,Y中间的H 认为是中心。所以在最大sco值之中要选一个周围H 最多的作为中心。代码我还没来得及改。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<queue>
 6 #define maxn 305
 7 using namespace std;
 8 const int zl[2][4]={{0,1,-1,0},{1,0,0,-1}};
 9 int num,n,m,mp[maxn][maxn],sco[maxn][maxn],ans1,ans2;
10 void dfs(int d)
11 {
12     for (int i=1;i<=n;i++)
13       for (int j=1;j<=m;j++)
14       if (mp[i][j]==1&&sco[i][j]==-1){
15           for (int k=0;k<=3;k++)
16           {
17               int x=i+zl[0][k],y=j+zl[1][k];
18               if (sco[x][y]!=-1&&sco[x][y]<=d){
19                     sco[i][j]=d+1;
20                     num--;
21                 if (num==0) return ;
22                 break;
23             }
24           }
25       }
26     dfs(d+1);
27 }
28 int main()
29 {
30     freopen("calm.in","r",stdin);
31     freopen("calm.out","w",stdout);
32     cin>>n>>m;
33     memset(sco,-1,sizeof(sco));
34     for (int i=1;i<=n;i++)
35     {
36         char a[maxn];
37         scanf("%s",a);
38         for (int j=0;j<m;j++)
39         {
40             if (a[j]==‘Y‘||a[j]==‘X‘) mp[i][j+1]=3;
41             else if (a[j]==‘H‘) {
42                 mp[i][j+1]=1;num++;
43             }
44             else{
45                 mp[i][j+1]=2;
46                 sco[i][j+1]=0;
47             }
48         }
49     }
50     dfs(0);
51     int ma=0,mm=-1;
52     for (int i=n;i>=1;i--)
53       for (int j=m;j>=1;j--)
54          if (sco[i][j]>=ma){
55                 ma=sco[i][j];
56                  ans1=i;ans2=j;
57          }
58     cout<<ans1<<" "<<ans2;
59     return 0;
60 }

   

时间: 2024-10-27 10:22:28

【NOIP模拟_54测试】【并查集】【二进制】【搜索】【区间序列类】的相关文章

使用并查集来维护不同的类关系

我们理解并查集这个数据结构的时候不要过于死板,我们要知道 并查集是用来维护关系的,而不是单纯一味去归并,归并,归并 下面给出一个问题尝试用并查集来解决:一共有两个类,然后告诉你若干组数据,每一组数据的两个元素不是一类的,然后在线判断两个元素是否是同一类 这个时候如果你只会归并就行不通的,还需要一些特殊的处理 我们需要在并查集的那个数组的基础之上,需要另一个数组来记录这种特殊的现象 int set[maxn],a[maxn]; //a表示这个节点和父节点的关系,0表示相同1表示不同 接下来我们的路

【NOIP模拟】board(线段树维护二进制,树序号化为二进制)

题目背景 SOURCE:NOIP2016-RZZ-2 T3 题目描述 给出这样一棵“二叉树”: 每个节点有左右两个儿子,并如下定义每个节点的高度:假设父亲节点的高度为 h ,那么他的两个儿子的节点的高度都是 h + 1 ,相同高度的所有节点称作一层. 每个节点的左儿子的子树都在右儿子的子树的左边,每一层相邻的两个节点之间有一条边. 下面是一个例子: 每一条图上的路径用一个字符串表示,字符串中的每一个字符表示一个移动.字符仅包含如下五种: 1:表示移动到当前节点的左儿子 2:表示移动到当前节点的右

【noip模拟题】日历游戏(博弈论+搜索)

直接搜索即可... 注意不要爆栈..所以我们可以分块搜索... 然后太懒且太弱我就不写了... orz hzwer [问题描述] moreD和moreD的宠物CD正在玩一个日历游戏,开始时,他们从1900年1月1日到2012年12月22日(你懂的……)选一个日期开始,依次按照如下规则之一向后跳日期: 1. 跳到日历上的下一天. 2. 跳到日历上的下个月的同一天(如果不存在,则不能这么做). 要是谁正好到达2012年12月22日那么他就赢了,如果到达这天之后的日期那他就输了——原因你也懂的. 每次

2-XOR-SAT (种类并查集)

写了那么多模拟题这题算是最难的了QAQ 好神,,,我于是补了一下并查集.. 并查集很神...... orz 种类并查集...orz 对于维护sat,我们可以这样想: 如果x和y的xor是true,那么x和y肯定不一样,那么我们有s[x]=s[y]^1 否则s[x]=s[y] 我们需要维护的是一系列的x和y之间的关系,那么我们考虑用并查集维护这个 区间! 注意这个一定是区间的概念! 因为只有区间才能满足区间性质! 比如 x xor y xor z = true 而我们得知了x xor y的值,那么

POJ 1182 食物链(带权并查集)

http://poj.org/problem?id=1182 题意: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是"1 X Y",表示X和Y是同类. 第二种说法是"2 X Y",表示X吃Y. 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话

小结:并查集

复杂度: O(n*α(n)) 其中α(x),对于x=宇宙中原子数之和,α(x)不大于4 .(对于nocow里的复杂度我也是醉了) 概要: 并查集就是一个数组和一行话. 应用: 图的连通.集合操作.生成树的合并等 技巧及注意: 并查集是个好东西. 维护区间+前缀和:对于一些连续的区间,我们要判断这些区间是否合法,带修改.这种题我们可以考虑并查集来维护区间,用前缀和维护信息,而在并查集按秩合并的时候,一定要注意合并前和合并后如何维护信息,比如这题[BZOJ]1202: [HNOI2005]狡猾的商人

2012长春站B题 zoj 3656 并查集

好像大神都用的是2-sat,其实我也有想过.因为我碰到过的判断yes or no的题目就那么几种(2-sat,并查集,搜索,博弈),(因为本人比较水,所以就碰到了这几种,看来以后还是要多做体检积累经验:)),但是比赛的时候还是用了并查集,下面是我的并查集解法: 把b[][]数组上的每个位拆开成两个点i和i',(不超过32位),另外新加两个点0和1,如果确定某点i对应的是0,则i与0点合并,i'点与1点合并:如果确定某点i对应的是1,则i与1合并,i'与0合并:如果确定两点i和j对应的位是相反的数

[CSP-S模拟测试]:Dash Speed(线段树+并查集+LCA)

题目描述 比特山是比特镇的飙车圣地.在比特山上一共有$n$个广场,编号依次为$1$到$n$,这些广场之间通过$n−1$条双向车道直接或间接地连接在一起,形成了一棵树的结构. 因为每条车道的修建时间以及建筑材料都不尽相同,所以可以用两个数字$l_i,r_i$量化地表示一条车道的承受区间,只有当汽车以不小于$l_i$且不大于$r_i$的速度经过这条车道时,才不会对路面造成伤害. $Byteasar$最近新买了一辆跑车,他想在比特山飙一次车.$Byteasar$计划选择两个不同的点$S,T$,然后在它

贪心 + 并查集 之 CODE[VS] 1069 关押罪犯 2010年NOIP全国联赛提高组

/* 贪心 + 并查集 之 CODE[VS] 1069 关押罪犯  2010年NOIP全国联赛提高组 两座监狱,M组罪犯冲突,目标:第一个冲突事件的影响力最小. 依据冲突大小,将M组罪犯按从大到小排序,按照排序结果,依次把每组罪犯分开放入两个监狱, 直到当前这组罪犯已经在同一个监狱中了,此时即为答案. 实现: 1)通过不在同一个监狱的罪犯,推断出在同一个监狱的罪犯.(依据:一共就两个监狱)      ftr[b] = a+n   // a和b是在不同监狱 ftr[c] = a+n   // a和