您的位置:首页 > 其它

【模拟题】【集训系列1】【dp】【并查集】一套神奇的题

2016-10-31 20:16 260 查看
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

唉就是推…类似题:紫书P242 防线(UVa1471)

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=(1e5)+5;
int n,ex[N],now[N],now2[N],f[N][4],ans;//0will,1ed,2ing
int main()
{
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&ex[i]);
ex[0]=-1;now[0]=-1;
for(int i=1;i<=n;i++)
{
if(ex[i]>ex[i-1])
{
f[i][0]=f[i-1][0]+1;
f[i][1]=f[i-1][1]+1;
}
else
{
f[i][0]=1;
f[i][1]=1;
}
f[i][1]=max(f[i-1][3]+1,f[i][1]);

if(ex[i]>now[i-1])
f[i][1]=max(f[i][1],f[i-1][2]+1);

now[i]=ex[i-1]+1;
f[i][2]=f[i-1][0]+1;

now2[i]=ex[i+1]-1;
if(now2[i]>ex[i-1])f[i][3]=f[i-1][0]+1;
else f[i][3]=1;
}
for(int i=1;i<=n;i++)
{
ans=max(ans,f[i][0]);
ans=max(ans,f[i][1]);
ans=max(ans,f[i][2]);
}
printf("%d\n",ans);
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种可能。

这套题真的是格外有趣…

我们首先要读懂题意…

接着,上图:


显而易见,这两种情况就是特例啦~

然后这道题要用并查集来实现其查找的特殊情况辨别。

有点抽象?上图吧:



描述:

将左端的前一位指向右端!

为什么是前一位呢?因为要处理相邻的情况,而普通情况是不影响的,理解理解!

在判断这两种特殊情况时就很好处理啦!是不是很巧妙!!

上代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int N=100005,p=(1e9)+7;
int ans=1,n,m,fa
,x,y,fx,fy;
int findd(int x)
{
if(fa[x]==x)return x;
else return fa[x]=findd(fa[x]);
}
int main()
{
freopen("seg.in","r",stdin);
freopen("seg.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
fx=findd(x-1);
fy=findd(y);
if(fx!=fy)      //两种特殊情况的举例
{
fa[fx]=fy;
ans=(ans*2)%p;
}
}
printf("%d\n",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后,出现样例输入的地图。

P.S. Mushroom拜托他GF出的这题= =

T3莫名的画风有点不适应,然后其实其本身题目数据是有很多错误的…所以,在此提供一种最简单做法:

由邻近海洋的暖流内推,一层一层推回去,在最后的时候需要特判一下,因为有一些反例。

特判就是将最后剩下的无法再推中,取邻近暖流最多的那个点,因为多面为石或岸的点最后很可能和爱花同时推出来,正确的那个是邻近暖流最多的。

代码如下:(懒得写特判了….)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
const int N=305,ma=710;
int n,m,step[N][N],mov[2][4]={{0,0,1,-1},{1,-1,0,0}};
int live[2][N*N][2],tot[2],prev,now;
char mapp[N][N];
bool sym[N][N];
void prep()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
mapp[i][j]=getchar();
getchar();
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(mapp[i][j]=='H')
{
for(int k=0;k<=3;k++)
if(mapp[i+mov[0][k]][j+mov[1][k]]=='B')
sym[i][j]=true;
if(sym[i][j]){live[0][++tot[0]][0]=i;live[0][tot[0]][1]=j;}
}
}
bool worrk()
{
prev=0;now=1;
while(tot[prev]>1)
{
for(int i=1;i<=tot[prev];i++)
{
for(int k=0;k<=3;k++)
{
int xx=live[prev][i][0]+mov[0][k],yy=live[prev][i][1]+mov[1][k];
if(mapp[xx][yy]=='H'&&!sym[xx][yy])
{
sym[xx][yy]=true;
tot[now]++;
live[now][tot[now]][0]=xx;
live[now][tot[now]][1]=yy;
}
}
}
tot[prev]=0;
swap(prev,now);
}
printf("%d %d",live[prev][1][0],live[prev][1][1]);
}
int main()
{
freopen("calm.in","r",stdin);
freopen("calm.out","w",stdout);
scanf("%d%d",&n,&m);getchar();
prep();
worrk();
//printf("-1");
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp 巧妙