P4170 [CQOI2007]カラーリング(間隔dp)

トピックポータル

質問の意味:長さnの厚板を与えます。連続した長さの厚板を選択して、毎回同じ色で染めることができます。同じ場所で、後の色で前の色を覆うことができます。対象の色の厚板を渡して、少なくとも対象の厚板を染色するのに何回かかるかを尋ねます。(色は26個の大文字で表されます)

アイデア:彼は私たちに目標の長さにペイントする方法を見つけるように頼みました。逆に考えて、ボード全体を同じ色でペイントし、最後に答えに1を追加することができます。これが答えです。同じ色のブロックに別の色をペイントすることは、この別の色を元に戻すことと同じです。
私たちは、使用F [i]は[J] [C] [J] [C] [i]はFをf [ i ] [ j ] [ c ]は、区間[i、j] [i、j]を意味します[j ]すべてカラーccで塗装c必要な最小ステップ数。次に、トランジットポイントkkを列挙しますkと色ccc、それからあります

  • f [i] j] [c] = min(f [i] [j] [c]、f [i] [k] [c] + f [k + 1] [j] [c])f [i ] j] [c] = min(f [i] [j] [c]、f [i] [k] [c] + f [k + 1] [j] [c]) f [ i ] j ] [ c ]=m i n f [ i ] [ j ] [ c ] f [ i ] [ k ] [ c ]+f [ k+1 ] [ j ] [ c ]

ここで注目に値するのは、区間[i、j] [i、j][j ]、区間[i、k] + [k + 1、j] [i、k] + [k + 1、j]だけを使用することはできません[k ]+[ k+1 j ]は区間[i、j] [i、j]から変換されます[j ]は直接変換です。つまり、間隔全体が特定の色でペイントされた後、間隔全体が別の色に変更されます。したがって、上記の転送中に最小のf [i] [j] [c] f [i] [j] [c]を維持できます。f [ i ] [ j ] [ c ]、この最小値を使用してf [i] [j] [c] f [i] [j] [c]を更新しますf [ i ] [ j ] [ c ]

最後に、木のセクション全体を特定の色にペイントするための最小コストを見つけることができます。この最小コスト+ 1 +1+ 1は、空のボードからターゲットボードにペイントするために必要な最小ステップ数です。

コード:

#include<bits/stdc++.h>
#define endl '\n'
#define null NULL
#define ls p<<1
#define rs p<<1|1
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define ll long long
#define int long long
#define pii pair<int,int>
#define ull unsigned long long
#define pdd pair<double,double>
#define lowbit(x) x&-x
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read()
{
    
    
    int x=0,f=1;
    char ch=gc();
    while(ch<'0'||ch>'9')
    {
    
    
        if(ch=='-')
            f=-1;
        ch=gc();
    }
    while(ch>='0'&&ch<='9')
    {
    
    
        x=x*10+ch-'0';
        ch=gc();
    }
    return x*f;
}
using namespace std;
const int N=2e5+55;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
const double eps=1e-6;
const double PI=acos(-1);
char s[N];
int f[111][111][30];
void solve()
{
    
    
    cin>>s+1;
    int n=strlen(s+1);
    memset(f,0x3f,sizeof f);
    for(int i=1; i<=n; i++)
        for(char c='A'; c<='Z'; c++)
            f[i][i][(int)(c-'A')]=(s[i]==c?0:1);
    for(int len=2; len<=n; len++)
    {
    
    
        for(int i=1; i+len-1<=n; i++)
        {
    
    
            int j=i+len-1;
            for(int k=i; k<=j-1; k++)
            {
    
    
                int mi=1e18;
                for(char c='A'; c<='Z'; c++)
                {
    
    
                    int p=(int)(c-'A');
                    f[i][j][p]=min(f[i][j][p],f[i][k][p]+f[k+1][j][p]);
                    mi=min(mi,f[i][j][p]);
                }
                for(char c='A'; c<='Z'; c++)
                {
    
    
                    int p=(int)(c-'A');
                    f[i][j][p]=min(f[i][j][p],mi+1);
                }
            }
        }
    }
    int res=inf;
    for(char c='A'; c<='Z'; c++)
        res=min(res,f[1][n][(int)(c-'A')]);
    cout<<res+1<<endl;
}
signed main()
{
    
    
//    int t;
//    cin>>t;
//    while(t--)
    solve();
    return 0;
}


おすすめ

転載: blog.csdn.net/Joker_He/article/details/109678473