9月17号 NOIP模拟

来源:互联网 发布:网络综合布线工程预算 编辑:程序博客网 时间:2024/05/22 04:45

Mushroom 的序列

【问题描述】 Mushroom 手中有 n 个数排成一排,现在 Mushroom 想取一个连续的子序列,使得这个 子序列满足:最多只改变一个数,使得这个连续的子序列是严格上升子序列,Mushroom 想 知道这个序列的最长长度是多少。
【输入格式】 第一行一个整数 n,表示有 n 个数。 第二行为 n 个数。
【输出格式】 一个数,为最长长度。
【输入样例】 6 7 2 3 1 5 6
【输出样例】 5
【样例解释】 选择第 2 个数到第 6 个数,把 1 改变成 4 即可。 【数据范围】 对于 30%的数据,n<=10 对于 60%的数据,n<=1000 对于 100%的数据,n<=100000
1A过,用end表示从这个点开始所能延展到的最长上升连续子序列的长度,判断的时候就判断一下两端区间能不能连在一起就可以了,具体操作是如果这一段的最后一个和下一段的第二个之间的差超过或者等于2,那么可以,如果这一段的倒数第二个和下一段的第一个之间的差超过或者等于2,那么可以,否则就是这一段的长度加一,不断比较取max就可以了


#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int MAXN=100000+10;int a[MAXN],end[MAXN],n,maxn;int main(){    freopen("seq.in","r",stdin);    freopen("seq.out","w",stdout);    scanf("%d",&n);    for(register int i=1;i<=n;i++){        scanf("%d",&a[i]);        if(a[i]>a[i-1]) end[i]=end[i-1]+1;        else            end[i]=1;    }    for(register int i=n;i>=1;i--){        if(a[i-end[i]+1]-a[i-end[i]-1]>=2) maxn=max(end[i]+end[i-end[i]-1]+1,maxn);        if(a[i-end[i]+2]-a[i-end[i]]>=2)   maxn=max(end[i]+end[i-end[i]],maxn);        else                               maxn=max(end[i]+1,maxn);    }    printf("%d\n",maxn);    return 0;}

Mushroom 的区间

【题目描述】 Mushroom 有一行数,初始时全部是 0。现在 Mushroom 有 m 个区间[L,R],他希望用以 下操作得到新的序列。 从 m 个给定区间中选择一个区间[s,t],把区间中的数对应元素全部翻转。(0 变 1,1 变 0) 请告诉 Mushroom 他能得到多少区间。(模 10^9+7)
【输入格式】 第一行包含两个整数 n,m。表示 n 个数和 m 个区间。 接下来 m 行是所表示的区间。
【输出格式】 一个整数,表示能得到的区间数。
【样例输入】 3 3 1 1 2 2 3 3 【样例输出】 8
【数据范围】 对于 30%的数据,n,m<=20 对于 60%的数据,n,m<=100 对于 100%的数据,n,m<=100000
【样例解释】 每个位置都可以单个修改,所以有 8 种可能。


这道题自己原来的思路是错的,现在我们要判断重复的区间,举个例子,如果有1-3这个区间,4-5这个区间,还有个1-5这个区间,显然1-5可以被1-3和4-5的组合替代,所以我们采用并查集,每次查询l和r+1是否在同一个set里面,如果是的话说明这个区间可以被之前的一些区间表示出来,计数之后用二项式定理推论算一下快速乘或者直接乘就可以了

#include<cstdio>#include<iostream>#include<cstring>using namespace std;const int MAXN=100000+10;int n,m,fa[MAXN];long long ans=1;const int mod=1e9+7;namespace Union_set{    void init(){        for(register int i=1;i<=n;i++) fa[i]=i;    }    int find(int x){        if(x==fa[x]) return x;        else         return fa[x]=find(fa[x]);    }    void Union(int x,int y){        x=find(x);y=find(y);        fa[x]=y;    }}int main(){    using namespace Union_set;    scanf("%d%d",&n,&m);int te,mp;    init();    for(register int i=1;i<=m;i++){        scanf("%d%d",&te,&mp);        if(find(te)==find(mp+1)) continue;        else  Union(te,mp+1),ans=ans*2%mod;    }    printf("%I64d\n",ans);    return 0;} 

来自风平浪静的明天

【题目描述】 冬眠了五年,光终于从梦中醒来。 千咲、要,大家都在。 隐约记得“昨天”的海船祭,爱花意外成为贡女,沉入海底。 海面冰封,却有丝丝暖流在冰面之下涌动。 此时,爱花沉睡在祭海女神的墓地。她的胞衣在一点点脱落,化作一簇簇暖流,夹杂着她的 感情,向海面上涌去。 爱花,你在哪里?
五年之后,纺已经成为海洋学研究科的大学生。 在纺的帮助下,光得知了海面下海流的情况。 纺告诉光,暖流一旦产生,就会不断地向四周扩散,直到遇到海中的岩石。
红腹海牛,快告诉光,爱花在哪里。 纺帮你绘制了一张海流情况图,长度为 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 出的这题= =


没有任何技巧,暴力dfs记忆化一下就可以了,用dp[k][i][j]表示现在以(i,j)为暖流中心,问走k步(也就是bfs走k圈)是否合法,如果合法就return true,k从大往小枚举,因为小的可能会满足局部不能满足全局。


#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>using namespace std ;int movement[4][2]={{0,1},{0,-1},{1,0},{-1,0}} ;int N , M ;bool f[600][301][301] , v[600][301][301] ;char mp[305][305] ;bool dfs( int x, int y, int dep ) {    if ( dep == 0) return mp[x][y] != 'B';    if ( v[dep][x][y] ) return f[dep][x][y];    for ( register int i = 0; i < 4; i++ ){        int nx = x + movement[i][0],ny = y + movement[i][1];        if ( mp[nx][ny] == 'B' ) {            f[dep][x][y] = false ; break ;        } else if ( mp[nx][ny] == 'H' && !dfs( nx, ny, dep-1 ) ) {            f[dep][x][y] = false ; break;        }    }    v[dep][x][y] = true;    return f[dep][x][y];}void solve() {    for ( register int k = 0; k < N + M; k++ )        for ( register int i = 1; i <= N; i++ )             for ( register int j = 1; j <= M; j++ )                f[k][i][j]=true;    for( register int k = N + M - 1; k; k-- )        for( register int i = 1; i <= N; i++ )            for ( register  int j = 1; j <= M; j++ )                if( mp[i][j] == 'H' && dfs(i, j, k) ){                    printf( "%d %d\n", i, j);exit(0);                }} int main(){    char a;    scanf( "%d%d" , &N , &M ) ;    for ( register int i = 1; i <= N ; i ++ )        for ( register int j = 1; j <= M ; j ++ ) {            a = getchar();            while ( a != 'Y' && a != 'B' && a != 'X' && a != 'H') a = getchar();            mp[i][j] = a;        }    solve();    return 0;} 

这是我写的第一份空格的代码,不得不说,还真是好看了许多


总结:
这次考试虽然前半个小时就水完了t1t2,但是t2的推论有错误,没有考虑刚才所说的区间重复的问题,t3的正解也写挂了,考试的时候还需要沉下心来慢慢分析考虑,在实现一个算法之前,一定要先检验这个算法的正确性,而不是直接去敲,因为这次考试就是算法直接都错了,这件事情非常值得引起警觉

原创粉丝点击