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