[NOIP模拟][审题][数据结构][bfs/dp]

来源:互联网 发布:网络测试工具包 编辑:程序博客网 时间:2024/05/21 22:46

NOIP 模拟赛

T1: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

【解题思路】
连续二字很重要,,,所有这个和LIS完全没有关系,,
左边右两边同时扫一遍,预处理,然后枚举那个需要改变的点,这时有两种情况,如果a[i-1]-a[i-2]>=2那么这个答案即为左右两边的序列加这个点的最大值,如果不是这种情况,只能考虑单边。。。QAQ读错题

#include<iostream>#include<cstdio>#include<cmath>using namespace std;const int N=100050;int a[N],b[N],c[N],n;int main(){    freopen("seq.in","r",stdin);    freopen("seq.out","w",stdout);    scanf("%d",&n);    for(int i = 1; i <=n; i++)    scanf("%d",&a[i]);    b[1]=1;    for(int i = 2; i<= n; i++)    if(a[i]>a[i-1])b[i]=b[i-1]+1;    else b[i]=1;    c[n]=1;    for(int i=n-1;i>=1;i--)    if(a[i]<a[i+1])c[i]=c[i+1]+1;    else c[i]=1;    int ans=1;    for(int i = 1; i<= n; i++){        if(a[i+1]-a[i-1]>=2)            ans=max(ans,b[i-1]+c[i+1]+1);        ans=max(ans,b[i-1]);        ans=max(ans,c[i+1]);    }    cout<<ans<<endl;    return 0;}

T2: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___2___3___4___5___6
另一个区间1__2__3,还有一个区间3__4__5__6
那么可以得知这三个区间可以只用两个区间,无论那两个(注:不一定要两个小的),,任何两个都可以表示出。
再像1—2—3—4—5—6
1—2—3—4
3—4—5—6
3—4
同理上面任意3个都可以包含四个的这种情况。
所以这两种情况的价值区间个数是要–的,
这种可以dfs,搜索,记录vis,
然而并查集这个优美的东东更是特别好。
一个操作,,起点s,终点t,这两个点,把fa[t]==s;
那么相当于一个点的父亲即使这个操作的起点,,这样,对于上述的两种特殊情况,当处理最后一个区间的,发现他的起点终点都是一个fa,所以这个区间无价值。。
最后算出来的有价值区间为k个,那么,方案数目为2^k,因为每个区间有取与不取的情况。。。(这个地方自己竟然没想到==)。。
欸,风萧萧兮易水寒,,,,为何我没有想到,还是自己太蒟蒻了。。。。。。。。

#include<iostream>#include<cstring>#include<cstdio>#define FROP "seg"using namespace std;const int N=100050;int n,m,fa[N];int find(int x){    return (x==fa[x])?x:fa[x]=find(fa[x]);}const int mod=1e9+7;int kmi(int x){    if(x==0)return 1;    if(x==1)return 2;    int p=kmi(x/2)%mod;    if(x%2)return ((long long)p*p)*2%mod;    return (long long)p*p%mod;}int main(){    freopen(FROP".in","r",stdin);    freopen(FROP".out","w",stdout);    scanf("%d%d",&n,&m);    int ans=1;    for(int i = 1; i <= n; i++)        fa[i]=i;    for(int i = 1; i <= m; i++){        int a,b;        scanf("%d%d",&a,&b);        int x=find(a),y=find(b+1);        if(x^y){            fa[x]=y;            ans=(long long)ans*2%mod;        }    }    printf("%d",ans);    return 0;}

T3:来自风平浪静的明天

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

【题目思路】
可以bfs,这里不用dfs,因为很难判时间,,用bfs,这样一层也就是一个时间,,所以这里处理的很好,当一层放进去后加一个标志,q.push(-1),当q.front()==-1时,说明这一层已经扫完,然后再看是否已经扫完所有的‘H’
也可以用dp,没看,这里贴出来就好了。。。
哦,还有,用bfs 需要自己写队列,不然会超时一组。。。。

#include<iostream>#include<cstdio>#include<ctime>#include<cstring>#include<cmath>#include<algorithm>#include<string>#include<map>#include<set>#include<cstdlib>#include<queue>#include<vector>#ifdef WIN32#define AUTO "%I64d"#else #define AUTO "%lld"#endifusing namespace std;#define FROP "calm"const int  N = 305;#define cle(x) memset(x,0,sizeof(x))int n,m,up,down,li,ri;char a[N][N];int b[N][N],T,anx,any,tot,num;bool bo[N][N];const int con[2][4]={-1,1,0,0,0,0,-1,1};const char ch[3]={'H','B','x'};void init(){    getchar();    up=n,down=1,li=m,ri=1;    for(int i = 1; i <= n; i++){        for(int j = 1; j <= m; j++){            a[i][j]=getchar();            if(a[i][j]=='H')num++;        }        getchar();    }}int qx[N*N],qy[N*N];bool bfs(int x,int y){    cle(qx);    cle(qy);    cle(bo);    int head=1,tail=1;    qx[tail]=x;    qy[tail++]=y;    qx[tail]=-1;    qy[tail]=-1;    bo[x][y]=true;    int tt=num-1;    while(head<=tail){        int xx=qx[head],yy=qy[head];        head++;        if(xx!=-1){            for(int i = 0; i<4; i++){                int x1=xx+con[0][i],y1=yy+con[1][i];                if(x1>=1&&x1<=n&&y1>=1&&y1<=m&&!bo[x1][y1]){                    bo[x1][y1]=true;                    if(a[x1][y1]=='B')return false;                    if(a[x1][y1]=='H'){tt--;qx[++tail]=x1;qy[tail]=y1;}                }            }        }        else {            qx[++tail]=-1;            qy[tail]=-1;            if(tt==0)return true;        }    }}int main(){    freopen(FROP".in","r",stdin);    freopen(FROP".out","w",stdout);    scanf("%d%d",&n,&m);    init();    for(int i = 1;i<=n;i++)        for(int j = 1;j<=m;j++)if(a[i][j]=='H'){            if(bfs(i,j)){                printf("%d %d",i,j);                exit(0);            }        }    cout<<"-1"<<endl;    return 0;}

Flow[TIME][X][Y]表示暖流的初始位置是(X,Y),经过时间 TIME 以后,形成的图案会不会和海 流图不相符(不应是 H 的地方出现了 H 则不相符,应出现 H 的地方没有出现 H 认为相符)
YYYHB YYHHH YHHXB BBHBB BBBBB
海流图 YYYBB YYHHB YBHXB BBBBB BBBBB
相符的图(蓝色部分应该出现 H 但没有出现) YYYHH YYHHH YHHXH BHHHB BBHBB
不相符的图(红色部分不该出现 H 但出现了)
F[TIME][X][Y]=F[TIME-1][X-1][Y]&&F[TIME-1][X][Y-1]&&F[TIME-1][X+1][Y]&&F[TIME-1][X][Y+1]
记忆化 DP 时间复杂度 O(N^3) 空间复杂度 O(N^3)
找到最大的 TIME,对应的 X 和 Y 就是爱花的位置。 因为光相信自己一定能找到爱花,所以爱花的位置确定(不会有两个位置满足条件) 。

0 0