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