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;
}


 

 

 

 

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