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
题号:
CF Round_FF div1 A
题解:
”从头dp一遍,尾巴dp一遍。枚举要改的点,合并时它左边一个点向左和右边一个点向右的最长串,合并时判一下右边的点 是不是 大于 左边的点+1“
最开始看数据范围1e5,瞬间就想二分答案,check太麻烦了写不下去,然后忽然发现O(n)dp不就好了吗,这时候都已经过了1h了,真是糟糕。所以说不要面向数据范围编程啊。想好!想清楚!别急着动手!
我是顺着DP的,dp[i][0/1]表示到第i位 没有改过/改过的最长长度。
我的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100005;
int n,a[N],dp[N][2];
int max(int A,int B)
{
return A>B?A:B;
}
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]);
for(int i=1;i<=n;i++)
{
dp[i][0]=dp[i][1]=1;
if(i==1) continue;
dp[i][1]=2;
if(a[i]>a[i-1])
{
dp[i][0]=max(dp[i][0],dp[i-1][0]+1);
dp[i][1]=max(dp[i][1],dp[i-1][1]+1);
}
dp[i][1]=max(dp[i][1],dp[i][0]);
if(i==2) continue;
if(a[i]>a[i-2]+1) dp[i][1]=max(dp[i][1],2+dp[i-2][0]);
dp[i][1]=max(dp[i][1],dp[i][0]);
}
int ans=0;
for(int i=1;i<=n;i++)
ans=max(ans,max(dp[i][0],dp[i][1]));
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种可能。
题解:
”There are many mapping of this problem and I was very interested in knowing the one used in editorial. I reduced this problem to solving the rank of the matrix. Consider an M X N matrix ( M rows and N columns). Each row has elements either 0 or 1. Each row corresponds to one of the range given in the problem. Consider range li - ri, which corresponds to ith row in matrix. The elements from lith column to rith column in the row are 1 and other are 0. So we need to find the rank of the formed matrix. If rank is R, the solution of the problem is 2R.
The required rank can easily be found by simulating book method. First leave only one row with 1 in first column by carrying out suitable row subtractions. Then take on second column and so on. First sort the ranges in order of increasing first index, then subtract the ranges with same first index ( subtract smaller range from larger range).
Time Complexity: O(N log M)
http://discuss.codechef.com/questions/38498/chseq22-editorial“
之前有想到排掉等效的然后直接 2^x算,但是对于
|_||_ _|
|___|_|
这种情况没有想清楚,其实只要发现左右端点在一个并查集里面,就说明可以被表示啦,跟是被几个区间表示没有关系。
题解 : 若有x个不能被表示的区间,答案就是2^x
eg:
|_ _||_| , |___|_|
|_____| , |_||_ _|
读入一个区间,把他的左端点和右端点加入一个并查集。
(加l-1和r)
如果他的左右端点本来就在一个并查集了 ,那么它是可以被表示的,x- - 。
我的代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std;
const int mod=1e9+7;
const int N=100006;
int n,m,fa[N];
int getfa(int x)
{
if(fa[x]==x) return x;
else return fa[x]=getfa(fa[x]);
}
LL modpow(int A,int B)
{
LL ans=1; LL base=1LL*A;
for(;B;B>>=1)
{
if(B&1)
{
ans=((ans%mod)*(base%mod))%mod;
}
base=((base%mod)*(base%mod))%mod;
}
return ans;
}
int main()
{
freopen("seg.in","r",stdin);
freopen("seg.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=0;i<=n+1;i++) fa[i]=i;
int cnt=m;
for(int i=1;i<=m;i++)
{
int l,r; bool flag=0;
scanf("%d%d",&l,&r);
int fx=getfa(l-1); int fy=getfa(r);
if(fx==fy) cnt--;
if(fx!=fy) fa[fx]=fy;
}
printf("%I64d\n",modpow(2,cnt));
}
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出的这题= =
题解:
“
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就是爱花的位置。
因为光相信自己一定能找到爱花,所以爱花的位置确定(不会有两个位置满足条件)。”
我n^4log 70分,枚举H作为起点,spfa,比较到最近的B距离如果小于到最远的H的距离,就不合法。
暴搜n^4可以过,就枚举每个H作为起点bfs,到碰到一个B,停止,如果这时候还有H没有流到就不合法。
没有人写正解,怜悯(๑•́ωก̀๑)
总结一下,感觉到这个时候,读错题啊,很熟的算法写错这类的问题反而多了起来。有时候一眼看不到方向,就沉不下来去挖掘细节去思考。总是想不清楚,略过一些关键。跟我自己平时草稿杂乱也有关。对时间上还是压一下第一二题的时间,一旦放弃某一题的正解一定要先打个暴力再说。最后留半个小时去检查前面。
这段时间一直在搞DP,有时间还是要做一些恶心的代码题,代码能力和速度现在都要集中提高。