首页 > 其他分享 >CF1860D

CF1860D

时间:2023-08-25 15:33:05浏览次数:34  
标签:01 frac int times CF1860D dp 105

首先,设\(1\)有\(c_1\)个,\(0\)有\(c_0\)个

\(01\)串中数字间只有四种关系,分别是\(00\),\(01\),\(10\),\(11\)

不难发现,第一种和第四种的数量是固定的,为$ \frac { c_0 \times ( c_0 - 1 ) }{2} $ 和 $ \frac {c_1 \times ( c_1 - 1 )}{2}$

同时,另外两种加起来一共有\(c_1 \times c_0\)种

然后以\(1\)为例,容易得出

\[所有1的前面的数字个数的总和\ -\ 11对出现的次数=01对出现的次数 \]

\[\sum_{i=1}^n[s_i=1]-\frac {c_1 \times ( c_1 - 1 )}{2}=\frac{c_1 \times c_0}{2} \]

同理

\[\sum_{i=1}^n[s_i=1]-\frac {c_1 \times ( c_1 - 1 )}{2}=\frac{c_1 \times c_0}{2} \]

设\(dp_{i,j,k}\)为前\(i\)个放\(j\)个\(0\),\(0\)的下标\(-1\)的和为\(k\)的最小逆转次数

答案即为\(dp_{n,c_0,\frac{c_1 \times c_0}{2}}\)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
char s[105];
int a[105];
int dp[105][55][5005];
void solve(){
    scanf("%s",s+1);
    int n=strlen(s+1),c1=0,c0;
    for(int i=1;i<=n;i++)
        a[i]=s[i]-'0';
    for(int i=1;i<=n;i++)
        c1+=a[i];
    c0=n-c1;
    if(c1<c0){
        for(int i=1;i<=n;i++)
            a[i]^=1;
        swap(c1,c0);
    }
    int s1,s0;
    s1=(n*(n-1)/2+c1*(c1-1)/2-c0*(c0-1)/2)/2;
    s0=n*(n-1)/2-s1;
    for(int i=0;i<=n;i++)
        for(int j=0;j<=c0;j++)
            for(int k=0;k<=s0;k++)
                dp[i][j][k]=1e9;
    dp[0][0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=min(c0,i);j++)
            for(int k=0;k<=s0;k++){
                if(j&&k>=i-1)dp[i][j][k]=min(dp[i][j][k],dp[i-1][j-1][k-(i-1)]+a[i]);
                dp[i][j][k]=min(dp[i][j][k],dp[i-1][j][k]+(a[i]^1));
            }
    printf("%d\n",dp[n][c0][s0]/2);
}
int main(){
    int t=1;
    //scanf("%d",&t);
    while(t--)solve();
    return 0;
}

标签:01,frac,int,times,CF1860D,dp,105
From: https://www.cnblogs.com/Linxrain/p/17657098.html

相关文章

  • CF1860D
    原题翻译补题的时候想了半天交换后对01和10个数的影响,写了半天的dp才发现前面的修改会影响0和1的个数(我是shabi)不过我感觉应该还是可做的直接说正解。首先显然我们不需要同时记录0的个数和1的个数,因为知道一个可以通过\(i-cnt\)得到另一个仔细一想,我们其实也不需要同时记录......