Codeforces Beta Round #98 (Div. 2) zstu-caicai写于 2011-12-18 11:30

我决定:以后每一场codeforces我都将进行总结,尽量在赛后把题目AK(*_*),水平有限,只能说尽量。

难得有一场CF的比赛在白天开始,于是我准时的守候在电脑前准备打一场CF,哈哈

a题b题很快过了,c题卡了一下,原因是在poj做过类似的一道题,http://www.cnblogs.com/wuyiqi/archive/2011/09/20/2182986.html

但是这道题目只需要求有几个区间能被其他区间完全覆盖,并不需要求每个区间分别能被几个区间覆盖,这是本质差别

对于这道题,只需要排个序(没必要用树状数组)x递增,y递减

所以后面的x肯定大于等于前面的x,现在只需要比较y即可,如果y小于maxy,则代表当前区间可以放进前面的某个区间,maxy代表前面最大的y

E题看到貌似是DP,但没想法,直接跳过

F题想到了用树状数组做,没做出来。。。。

最后看了别人的F代码,有线段树的,二分的,还有RMQ的,看得我晕乎乎的,最后找了份树状数组的(比较喜欢树状数组)研究了起来,这一看就是好久啊

今天晚上终于搞懂了

首先把元音字母记为-1,辅音记为2,这样题目就转换为了求最长的一段子序列的长度并保证序列和大于0

我们可以再进行转换,用sum[i]表示前i项的和,这样就变成了求相差最大的下标(i、j)之间的距离,sum[j]-sum[i]>=0;

这时,树状数组就派上用场了,每次做数据结构的题目我都喜欢往细了讲,有利于更好地理解*_*:

对于每个下标i,求出值小于等于sum[i]的最小下标,树状数组c[x]用来保存x统治的结点中(当然这些结点的值肯定小于x)的最小的下标

每次更新的时候更新统治x的结点(当然这些结点肯定大于x)的最小下标

而后还有询问,因为树状数组中已经存在的信息,都是sum[i]前面的数造成的,所以询问时在树状数组中直接向前找最小的下标,那些下标肯定是在i的前面的

好了,我们可以直接遍历一遍整个sum[]找出最长的想要的答案,还不懂看代码就可以了

A

View Code
#include<cstdio>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
char s[110];
while(scanf("%s",s)!=EOF)
{
int len=strlen(s);
int sum=1;
int ans=0;
int flag=0;
int i=0,k=0;
while(1)
{
i++;
k=1;
while(s[i-1]==s[i]&&i<len)
{
k++;
i++;
}
ans+=(k+4)/5;
if(i>=len) break;
}
printf("%d\n",ans);
}
return 0;
}

 

B

View Code
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
int a[5010];
int main()
{
int n,i;
while(scanf("%d",&n)!=EOF)
{
for( i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
sort(a+1,a+n+1);
int tot=0;
if(a[1]>n) tot=1;
for(i=2;i<=n;i++)
{
if(a[i]==a[i-1]||a[i]>n)
{
tot++;
}
}
printf("%d\n",tot);
}
return 0;
}

 

 

C

View Code
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100010
struct data
{
int x,y;
}a[MAXN];
int n;
int max(int a,int b)
{
return a>b?a:b;
}
bool cmp(const data &a, const data &b)
{
return a.x<b.x || a.x==b.x && a.y>b.y;
}
void init()
{
scanf("%d",&n);
for (int i=0; i<n; i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
sort(a,a+n,cmp);
}
void solve()
{
int ret=0,MAX=a[0].y;
for (int i=1; i<n; i++)
{
if (a[i].y<MAX) ++ret;
MAX=max(a[i].y,MAX);
}
cout<<ret<<endl;
}
int main()
{
init();
solve();
return 0;
}

 

 

D ,dp以后有时间一定补上

 dp[i][j]代表前i个字符拼成j个回文串的最少代价

#include<map>

#include<set>

#include<iostream>

#include<string>

#include<cstdio>

#include<cstring>

#include<vector>

#include<cmath>

#include<algorithm>

using namespace std;

const int inf = ~0u>>2;

const int maxn = 666;

int cost[maxn][maxn];

int dp[maxn][maxn];

int pre[maxn][maxn];

char s[maxn];

int gao(int f,int t)

{

	int len=t-f+1,ret=0;

	for(int i=0;i<len/2;i++)

    {

		if(s[f+i]!=s[t-i]) ret++;

	}

	return ret;

}

void justdoit(int i,int j)

{

	int len=j-i+1;

	for(int k=0;k<(len+1)/2;k++)  printf("%c",s[k+i]);

	for(int k=0;k<len/2;k++)

	{

		printf("%c",s[i+len/2-1-k]);

	}

}

void print(int i,int j)

{

	//puts("bug");

	if(j==0) return ;

	int s=pre[i][j];

	print(s,j-1);

	if(s!=-1)  printf("+");

	justdoit(s+1,i);

}

int main()

{

	int m;

	scanf("%s",s);

	scanf("%d",&m);

	int len=strlen(s);

	for(int i=0;i<len;i++)

	{

		for(int j=i;j<len;j++)

		{

			cost[i][j]=gao(i,j);

		}

	}

	fill(dp[0],dp[len+1],inf);

	memset(pre,-1,sizeof(pre));

	for(int i=0;i<len;i++)

	{

		dp[i][1]=cost[0][i];

		for(int j=1;j<=m;j++)

		{

			for(int k=0;k<i;k++)

			{

				if(dp[k][j-1]+cost[k+1][i]<dp[i][j])

				{

					dp[i][j]=dp[k][j-1]+cost[k+1][i];

					pre[i][j]=k;

				//	printf("i=%d j=%d %d\n",i,j,dp[i][j]);

				}

			}

		}

	}

	int ans=inf;

//	printf("%d\n",dp[6][5]);

	for(int i=1;i<=m;i++) ans=min(ans,dp[len-1][i]);

	printf("%d\n",ans);

	for(int i=1;i<=m;i++)

	{

		if(dp[len-1][i]==ans) 

		{

			print(len-1,i);

			break;

		}

	}

	return 0;

}

  

E

View Code
#include<stdio.h>
#include<string.h>
#include<ctype.h>
const int MAXN = 200001,INF=1000000000;
int n,MAX,sum[MAXN],c[3*MAXN];
char s[MAXN];
int min(int a,int b){
return a<b?a:b;
}
int max(int a,int b){
return a>b?a:b;
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int id)
{
while(x<=MAX)
{
c[x]=min(c[x],id);
x += lowbit(x);
}
}
int query(int x)
{
int least = INF;
while(x>0)
{
least = min ( least , c[x] );
x -= lowbit(x);
}
return least;
}
bool isvowel(char c)
{
c=tolower(c);
return c=='a' || c=='e' || c=='i' || c=='o' || c=='u';
}
int main()
{
memset(c,127,sizeof(c));
scanf("%s",s);
n = strlen(s);
MAX = 3 * n + 1;//因为下面的元素都加上了n+1
sum[0] = 0;
int i;
for(i = 0; i < n; i++)
sum[i+1] = sum[i] + (isvowel (s[i]) ? -1 : 2);
int longest = -INF;
for(i = 0;i <= n; i++)
{
int value = sum[i] + n + 1;//确保value > 0
longest = max (longest , i - query(value));//query()求出小于sum[i]的最小的下标
update(value,i);
}
if(longest <= 0){
printf("No solution\n");
return 0;
}
int count=0;
for(i = 0; i + longest <= n ; i++)
if(sum[i+longest]>=sum[i])
count++;
printf("%d %d\n",longest,count);
return 0;
}







你可能感兴趣的:(codeforces)