zoukankan      html  css  js  c++  java
  • UVa 11552 最小的块数(序列划分模型:状态设计)

    https://vjudge.net/problem/UVA-11552

    题意:
    输入一个正整数k和字符串S,字符串的长度保证为k的倍数。把S的字符按照从左到右的顺序每k个分成一组,每组之间可以任意重排,但组与组之间的先后顺序应保持不变。你的任务是让重排后的字符串包含尽量少的“块”,其中每个块为连续的相同字母。

    思路:

    令d【i】【j】表示第i组中第j位为末尾时的最小块数。

    对于第【i】组,我们首先计算出它的块数,即不同字母的个数。

    接下来枚举【i】组中第j个字母作为末尾时的情况,根据第【i-1】组中的字母,如果【i-1】中有和第【i】组相同的字母,此时如果【i】组只有一个块或者相同的字母不在【i】组末尾时:

    d[i][j]=min(d[i][j],d[i-1][p]+chunk-1);

    这样就可以前后相同的相连,减少一个块。

    没有相同的字母的话那就只能是两者块相加了:

    d[i][j]=min(d[i][j],d[i-1][p]+chunk);
     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<sstream>
     6 #include<vector>
     7 #include<stack>
     8 #include<queue>
     9 #include<cmath>
    10 #include<map>
    11 using namespace std;
    12 typedef long long LL;
    13 typedef pair<int,int> pll;
    14 const int INF=0x3f3f3f3f;
    15 const int maxn=1000+5;
    16 
    17 int k;
    18 char str[maxn];
    19 int d[maxn][maxn];
    20 int vis[150];
    21 
    22 int main()
    23 {
    24     //freopen("D:\input.txt","r",stdin);
    25     int T;
    26     scanf("%d",&T);
    27     while(T--)
    28     {
    29         scanf("%d",&k);
    30         scanf("%s",&str);
    31         int len=strlen(str);
    32         memset(d,INF,sizeof(d));
    33 
    34         for(int i=0;i<len/k;i++)
    35         {
    36             memset(vis,0,sizeof(vis));
    37             for(int j=0;j<k;j++)
    38             {
    39                 int t=i*k+j;
    40                 vis[str[t]]=1;
    41             }
    42 
    43             int chunk=0;
    44             for(int c='a';c<='z';c++)
    45                 if(vis[c])   chunk++;
    46 
    47             if(i==0)   //第一组的话直接赋值
    48                 for(int j=0;j<k;j++)
    49                 d[i][j]=chunk;
    50             else
    51             {
    52                 for(int j=0;j<k;j++)
    53                 {
    54                     int t=i*k+j;
    55                     for(int p=0;p<k;p++)  //考虑第i-1组的各个字母
    56                     {
    57                         int pre=(i-1)*k+p;   
    58                         if(vis[str[pre]] && (chunk==1||str[pre]!=str[t]))
    59                             d[i][j]=min(d[i][j],d[i-1][p]+chunk-1);
    60                         else d[i][j]=min(d[i][j],d[i-1][p]+chunk);
    61                     }
    62                 }
    63             }
    64         }
    65 
    66         int ans=INF;
    67         for(int i=0;i<k;i++)
    68             ans=min(ans,d[len/k-1][i]);
    69         printf("%d
    ",ans);
    70     }
    71     return 0;
    72 }
  • 相关阅读:
    SPOJ Distinct Substrings(后缀数组求不同子串个数,好题)
    POJ 1743 Musical Theme(后缀数组+二分答案)
    HDU 6191 Query on A Tree(可持久化Trie+DFS序)
    swust oj 1052
    swust oj 1051
    swust oj 1016
    swust oj 1014
    swust oj 1013
    swust oj 1012
    swust oj 1011
  • 原文地址:https://www.cnblogs.com/zyb993963526/p/6921268.html
Copyright © 2011-2022 走看看