uva11552

题意: 给一个长度为n的串n<1000然后将这个串平均分成k分,分别为 s1 s2 s3...sk,这k份中可以任意的交换字母位置 比如uuvuwwuv 切成两份 这样 uuvu 和wwuv 这样然后 重新整理一下就得到了 uuuv 和vuww 这样合并uv和vuw 在将两个合并 得到 uvuw 为4 个能在消的字符,问最后最小的结果是多少。刚开始考虑 交换他们的不同匹配,因为只要考虑两端就行了,贪心的进行交换结果wa了, 考虑dp[i][c]表示在第i部分的末尾放c的最小值,特判只有1种的情况 然后其他的 不能自己当头又当尾就行了 从前一个状态转移而来 如果有相同的就 +len[i]-1 否则就 +len[i]

dp[i][c]=min(dp[i-1][j]+v)j!=c 特判 1  ,v= i中有没有j ?len[i]-1:len[i];

#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
using namespace std;
const int maxn = 1005;
int dp[maxn][30];
int ch[maxn][30];
int len[maxn];
vector<int> common[maxn];
char str[maxn];
int k,num;
void inti(int n ){
     for(int i=0; i<=n; ++i)
         for(int j=0; j<26; ++j)
           dp[i][j]=maxn;
}
int main()
{
     int cas;
     scanf("%d",&cas);
     for(int cc=1; cc<=cas; ++cc){
         scanf("%d%s",&k,str);
         int L = strlen(str);
         num=1;
         for(int i=0; i<L; i+=k){
            len[num]=0;
            memset(ch[num],0,sizeof(ch[num]));
            for(int j=i; j<i+k; ++j) ch[num][str[j]-‘a‘]=1;
            common[num].clear();
            for(int j=0; j<26; ++j)
                if(ch[num][j]==1){
                     common[num].push_back(j);
                     len[num]++;
                }
            num++;
        }
        inti(num);
        for(int i=0; i<common[1].size(); ++i)
            dp[1][common[1][i]]=len[1];
        for(int i=2; i<num; ++i){
            int sz=len[i];
            if(sz==1){
                int t=common[i][0];
                for(int j=0; j<26; ++j)
                    if(t==j) dp[i][t]=min(dp[i][t],dp[i-1][j]+sz-1);
                    else dp[i][t]=min(dp[i][t],dp[i-1][j]+sz);
            }else {
                for(int j=0; j<26; ++j)
                   for(int d=0; d<sz; ++d){
                       int t=common[i][d];
                       if(ch[i][j]==1&&t!=j)
                            dp[i][t]=min(dp[i][t],dp[i-1][j]+sz-1);
                       if(ch[i][j]==0) dp[i][t]=min(dp[i][t],dp[i-1][j]+sz);
                   }
            }
        }
        int ans=maxn;
        for(int i=0; i<26; ++i)
            ans=min(ans,dp[num-1][i]);
        printf("%d\n",ans);
     }

    return 0;
}

时间: 2024-10-02 05:40:21

uva11552的相关文章

UVa 11552 最小的块数(序列划分模型:状态设计)

https://vjudge.net/problem/UVA-11552 题意:输入一个正整数k和字符串S,字符串的长度保证为k的倍数.把S的字符按照从左到右的顺序每k个分成一组,每组之间可以任意重排,但组与组之间的先后顺序应保持不变.你的任务是让重排后的字符串包含尽量少的“块”,其中每个块为连续的相同字母. 思路: 令d[i][j]表示第i组中第j位为末尾时的最小块数. 对于第[i]组,我们首先计算出它的块数,即不同字母的个数. 接下来枚举[i]组中第j个字母作为末尾时的情况,根据第[i-1]