Codeforces Beta Round #98 (Div. 2)

题目地址:http://codeforces.com/contest/137

很久没做CF了,做了下练习。

A. 直接从左到右扫描一下就行了。

B.出现的就标记一下,然后再统计未标记的数的个数就行了。

 

C.先把左端点排序一下,然后扫描右端点数组,维护一个最大值maxs,当扫描到i时,只要满足a[i].r<maxs,

那么这个区间就被包含,因为这时存在一个右端点取最大值的 j,j<i,满足a[j].l<a[i].l && a[i].r<a[j].r;复杂度O(nlogn);

【代码】

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
using namespace std;
struct node
{
	int l;
	int r;
}a[100005];

int cmp(node p,node q)
{
	return p.l<q.l;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
	{
		for(int i=1;i<=n;i++)
			scanf("%d %d",&a[i].l,&a[i].r);
		sort(a+1,a+n+1,cmp);

		int sum=0;
		int maxs=a[1].r;
        for(int i=2;i<=n;i++)
		{
           if(a[i].r<maxs)
			   sum+=1;
		   else
			   maxs=a[i].r;
		}
		printf("%d\n",sum);
	}
	return 0;
}


 

D. dp, 先预处理cnt[][]数组,cnt[i][j]表示把[i,j]这个区间变为回文窜的最小改变字母数。

dp[i][j]表示前i个字符,分为j个回文窜的最小改变字母数。

状态转移方程为 dp[i][j]=min(dp[i][j],dp[p][j-1]+cnt[p+1][i]); (p>=0 && p<i);

最后的结果就是min(dp[lens-1][i]) ; (i>=1 && i<=k);

用一个prei[][]数组记录一下路径就行了。复杂度O(n^3).

【代码】

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <cmath>
#include <vector>
using namespace std;

const int maxn = 505;

char str[maxn];
int  cnt[maxn][maxn];
int  dp[maxn][maxn];
int prei[maxn][maxn];
int ant[maxn];

int MakePalindromes(int l,int r)
{
	int sum=0;
    for(int i=l,j=r;i<j;i++,j--)
    {
       if(str[i]!=str[j])
		  sum+=1;
	}
	return sum;
}

void ChangetoPalindromes(int l,int r)
{
	for(int i=l,j=r;i<j;i++,j--)
	{
		if(str[i]!=str[j])
			str[i]=str[j];
	}
	for(int i=l;i<=r;i++)
		printf("%c",str[i]);
}

int main()
{
	int k;
	while(scanf("%s",str)!=EOF)
	{
		scanf("%d",&k);
		int lens=strlen(str);
        memset(cnt,0,sizeof(cnt));
		memset(dp,0,sizeof(dp));
        memset(ant,0,sizeof(ant));


        for(int i=0;i<lens;i++)
			for(int j=i;j<lens;j++)
                cnt[i][j]=MakePalindromes(i,j);

		for(int i=0;i<lens;i++)
			dp[i][1]=cnt[0][i];

		for(int i=1;i<lens;i++)
		{
			for(int j=2;j<=k;j++)
			{
				dp[i][j]=1000000000;
                for(int p=0;p<i;p++)
				{
					if(dp[p][j-1]+cnt[p+1][i]<dp[i][j])
					{
					    dp[i][j]=dp[p][j-1]+cnt[p+1][i];
						prei[i][j]=p;
					}
				}
			}
		}

		int mins=1000000000;
		int minj=0;
		for(int i=1;i<=k;i++)
		{
            if(dp[lens-1][i]<mins)
			{
				mins=dp[lens-1][i];
				minj=i;
			}
		}
		printf("%d\n",mins);

        ant[minj]=lens-1;
		for(int i=minj-1;i>=1;i--)
            ant[i]=prei[ant[i+1]][i+1];

	/*	for(int i=1;i<=minj;i++)
			printf("%d ",ant[i]);
		printf("\n");*/

		ant[0]=-1;
		for(int i=1;i<=minj;i++)
		{
			ChangetoPalindromes(ant[i-1]+1,ant[i]);
			if(i<minj)
				printf("+");
			else
				printf("\n");
		}

	}
	return 0;
}


 

E.把辅音字母标记为2,元音字母标记为-1,令p[i]记录前i个元素的和,sum[i][j]表示i到j的元素和,那么sum[i][j]=p[j]-p[i-1];

那么对于一个固定的i,我们要找到一个满足sum[i][j]>=0的最大的j(j>=i).  我们把p[]数组建立一棵线段树,那么我们只

要遍历i,然后利用线段树可以在O(logn)的时间复杂度内找到满足条件的j,更新最大长度ans。

最后再遍历一遍找出所有长度为ans的情况sum。总的时间复杂度是O(nlogn)

 【代码】

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <string.h>
#include <cmath>
#include <vector>
using namespace std;
const int maxn = 200005;
const int inf =2147483647;
char str[maxn];
int p[maxn];

struct Treenode
{
   int maxs;
   int l;
   int r;
}T[maxn*4];

inline bool Isvowels(char ch)
{
	if(
	   ch=='A' || ch=='E' || ch=='I' || ch=='O' || ch=='U' || 
	   ch=='a' || ch=='e' || ch=='i' || ch=='o' || ch=='u'
	  )
	  return true;
	return false;

}

inline int Mymax(int a,int b)
{
	if(a>b)
		return a;
	else
		return b;
}
void Build(int t,int l,int r)
{
   T[t].l=l;
   T[t].r=r;
   T[t].maxs=-inf;
   if(l!=r)
   {
	   int mid=(l+r)/2;
	   Build(2*t,l,mid);
	   Build(2*t+1,mid+1,r);
   }
}

void Update(int t)
{
	if(T[t].l==T[t].r)
	{
		T[t].maxs=p[T[t].l];
		return ;
	}
	int mid=(T[t].l+T[t].r)/2;
	Update(2*t);
	Update(2*t+1);
	T[t].maxs=Mymax(T[2*t].maxs,T[2*t+1].maxs);
	return ;
}

int Findmaxj(int t,int l,int r,int v)
{
    if(T[t].l==T[t].r)
	{
		if(T[t].maxs>=v)
			return T[t].l;
		return -1;
	}

	int mid=(T[t].l+T[t].r)/2;

	if(l>=mid+1 && T[2*t+1].maxs>=v)
	{
		int j=Findmaxj(2*t+1,l,r,v);
		if(j!=-1)
			return j;
	}

	if(l<=mid && r>=mid+1 && T[2*t+1].maxs>=v)
	{
		int j=Findmaxj(2*t+1,mid+1,r,v);
		if(j!=-1)
			return j;
	}

	if(r<=mid && T[2*t].maxs>=v)
	{
		int j=Findmaxj(2*t,l,r,v);
		if(j!=-1)
			return j;
	}

    if(l<=mid && r>=mid+1 && T[2*t].maxs>=v)
	{
		int j= Findmaxj(2*t,l,mid,v);
		if(j!=-1)
			return j;
	}

	return -1;
}

int main()
{
    while(scanf("%s",str+1)!=EOF)
	{
        int lens=strlen(str+1);
		p[0]=0;
		for(int i=1;i<=lens;i++)
		{
            if(Isvowels(str[i])==true)
				p[i]=p[i-1]-1;
			else
				p[i]=p[i-1]+2;
		}
		Build(1,1,lens);	
        Update(1);

		int ans=-inf;
		for(int i=1;i<=lens;i++)
		{
			int j=Findmaxj(1,i,lens,p[i-1]);
			if(j==-1)
				continue;
            if(j-i+1>ans)
				ans=j-i+1;
		}
        if(ans==-inf)
		{
			printf("No solution\n");
			continue;
		}
		int sum=0;
		for(int i=1;i<=lens-ans+1;i++)
		{
            int j=i+ans-1;
			if(p[j]-p[i-1]>=0)
               sum+=1;
		}
		printf("%d %d\n",ans,sum);
	}
	return 0;
}


 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章