Codeforces Beta Round #98 (Div. 2)

 

A .Postcards and photos

在这里卡了很久,主要是模拟时应该累加的条件没分析清楚.

初始times=0,carry=1,cur=str[0];//表示当前搬运的次数和当前携带的物品数.

当str[i]!=cur时 说明遇到了不同种类的物品,这时应该把手上的物品搬走并拿起str[i]因此执行

times++;carry=1;

主要问题是出在有5+个相同物品时的情形;
carry==5这时已经拿不下,但是不能直接执行

times++;carry=0;

错在:如果后面是一个不同种类的物品, 会因为str[i]!=cur再执行一次times++,这样就重复计算了;

正确的应该是if(carry>5){times++;carry=1;}

 

B. Permutation

应该是最水的一道吧,但我居然看漏了一个条件,输入的ai可能大于n而要求不能大于n,这时应该记录替换次数......T_T

 

C.history

当时没搞懂题意,其实现在也没搞懂,YY应该是求覆盖子事件最多的那个历史事件的子事件数,这么写过了.

最多有10^5,一一枚举会超时,我想到的办法是:

先将所有历史事件当做一个node,记录begin和end,题目给出的begin和end都很大,不过由于没有事件会有相同的begin或者end,可以充分利用这个条件,将begin和end,改成将他们升序排列后的序号.

然后依次访问每一个事件,该事件的子事件数就是它end的标号.......

但这么做只在访问第1个事件时是正确的,如果是访问第2个事件,可能出现这种情况:

1  ,  2...... 1,  2    显然1事件不能是2事件的子事件 

begin        end

所以我们要减去那些begin在它前面且end也在它前面的事件数目,为了降低复杂度,我们可以每处理一个事件就将计数器累加,就不需要每次再查找了.

还需要注意,如果一个事件的end小于之前的事件,它应该跳过累加且不必访问,因为作为某个事件的子事件,它的子事件不可能是最大的.

View Code
 1 #include<stdio.h>
2 #include<string.h>
3 #include<stdlib.h>
4 #define size 100001
5 typedef struct node
6 {
7 long begin;
8 long end;
9 }node;
10 node h[size];
11 long statis[size];
12 long n;
13 int cmp_begin(const void* x,const void* y)
14 {
15 node a,b;
16 a=*(node*)x;b=*(node*)y;
17 if(a.begin>b.begin)return 1;
18 else return -1;
19 }
20 int cmp_end(const void* x,const void* y)
21 {
22 node a,b;
23 a=*(node*)x;b=*(node*)y;
24 if(a.end > b.end)return 1;
25 else return -1;
26 }
27 int main()
28 {
29 long i,max,max_end,flag;
30 scanf("%ld",&n);
31 for(i=0;i<n;i++)
32 scanf("%ld%ld",&h[i].begin,&h[i].end);
33 qsort(h,n,sizeof(node),cmp_begin);
34 for(i=0;i<n;i++)
35 h[i].begin=i;
36 qsort(h,n,sizeof(node),cmp_end);
37 for(i=0;i<n;i++)
38 h[i].end=i;
39 qsort(h,n,sizeof(node),cmp_begin);
40 for(i=0,max_end=0,flag=0;i<n;i++)
41 {
42 if(max_end>h[i].end)continue;
43 max_end=h[i].end;
44 statis[i]=h[i].end-flag;
45 flag++;
46 }
47 for(i=0,max=0;i<n;i++)
48 if(statis[i]>max)max=statis[i];
49 printf("%ld\n",max);
50 return 0;
51 }
//代码只有这么短,喂马的比赛时候就想不到呢- -


D.Palindromes

比较开放的一道题,输出的答案不是唯一的,但是最小步数要保证正确.

求最小步数用dp.定义f[i][j]:将前i个字符串分划成j份回文所需要的代价.

那么第i个字符必定是属于第j个回文的,设它的长度为l,则有f[i-l][j-1]+diff(i-l+1,i)=f[i][j];

从1~i中找出使f[i][j]最小的l即可.

注意初始化f[0][0]=0,其它都为inf,  f[0][i]是非法状态,也应该设置为inf.

最后输出字符串时反向查找.

View Code
void find(int end,int rest)
{ 
  if(rest==0)return;
  for(l=1;l<=end;l++)
  if(f[end][rest]=f[end-l+1][rest-1]+diff(end-l+1,end))break;
  
  find(end-l,rest-1);
  print_ans(end-l+1,end);
}


 E.Last chance

 要的到最长的合法序列长度和个数,定义f[i]为以第i个字符开头的最长合法序列的长度是最自然地想法,这样查找个数会很方便.

 先预处理一下:累加f[i].v,f[i].c, 这样只要在后面找到一个j满足 f[j].v-f[i].v<=2(f[j].c - f[i].c)就说明第i+1~j为一个合法串,

 将不等式做一下变形得:  f[j].v - 2*f[j].c <= f[i].v -2*f[i].c  (这一步很关键,同时我也学到了,对题目条件做一些数学处理会让问题简化很多.)

 再添加一个域dif来保存v-2c,这样问题化简为:对f[i].dif 找到一个j使f[j].dif<=f[i].dif 且j>i;

 于是我们可以在预处理过程中 对每个dif的值保存一个最大的下标big[dif]

 直接判断big[dif]是否大于i ,若是则更新为最大值.

 需要注意2点:

 1.   如果当前字符str[i]为辅音,f[i].l的初始值应该为1否则为0;

 2.   要考虑恰好以第1个字符为开头的合法串.

你可能感兴趣的:(codeforces)