您的位置:首页 > 理论基础 > 数据结构算法

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

2016-10-31 19:42 183 查看
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
,b
,c
,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
=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
;
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;

4000
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"
#endif
using 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

;
int b

,T,anx,any,tot,num;
bool bo

;
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 就是爱花的位置。 因为光相信自己一定能找到爱花,所以爱花的位置确定(不会有两个位置满足条件) 。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: