题目地址: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;
}