E - Swap

E - Swap Editorial


Time Limit: 2 sec / Memory Limit: 1024 MB

Score : 500500 points

Problem Statement

Given is a string SS consisting of KEY.

How many strings are there that can be obtained with at most KK swaps of two adjacent characters in SS?

Constraints

  • 2 \leq |S| \leq 302≤∣S∣≤30
  • 0 \leq K \leq 10^90≤K≤109
  • SS consists of KEY.

Input

Input is given from Standard Input in the following format:

SS
KK

Output

Print the answer.


Sample Input 1 Copy

Copy

KEY
1

Sample Output 1 Copy

Copy

3

With at most one swap, there are three strings that can be obtained: KEYEKYKYE.


Sample Input 2 Copy

Copy

KKEE
2

Sample Output 2 Copy

Copy

4

With at most two swaps, there are four strings that can be obtained: KKEEKEKEEKKEKEEK.


Sample Input 3 Copy

Copy

KKEEYY
1000000000

Sample Output 3 Copy

Copy

90

 =========================================================================

此类题也只能说很难去证明为什么这样做不会缺失或者重复

EYEK

一维代表位置,二维代表e的个数,三维代表y的个数,四维代表交换次数

而按照正确方法我们得到的是如下结果

dp[1][1][0][0]=1

dp[1][1][0][1]=0

dp[1][1][0][2]=0

dp[1][1][0][3]=0

也就是交换两次结果也是0,可是如果我们把第二个e交换到第一个位置也是一种方法,而本题正确做法确实找到离当前e最近的那一个e进行转移。这就很让人不解

EYE为例

dp[2][2][0][0]为 1,显然不正确

但其转移到 dp[3][2][1][1]的时候,Y遍历E,会遇见一个比它大的E,也就把次数给加了上去。所以我们这样做是正确的。在累积多个相同字母时,如果我们没遇见其它字母,那么答案就一直是1种,(即先不计算与不同字母的交换),直到我们把不同字母提到前面,才产生了步数的变化和方案的累加。而且这么多不合理的1并不会影响答案,因为交换次数是0,我们最终获取答案的时候,仅仅取dp[n]的。

# include <iostream>
# include<vector>
# include<queue>
# include<map>
# include<vector>
# include<algorithm>
# include<cstring>
# include<iomanip>
# include<set>
# include<math.h>


using namespace std;
typedef long long int ll;

const int N=32;
const int C=N*(N-1)/2;

string s;
int K;

ll dp[N][N][N][C];

vector<int>kp,ep,yp;

int main()
{
    cin>>s>>K;

    s=" "+s;


    int n=s.size()-1;

    K=min(K,n*(n-1)/2);

    for(int i=1; i<=n; i++)
    {
        if(s[i]=='K')
        {
            kp.push_back(i);

        }
        else if(s[i]=='E')
        {
            ep.push_back(i);

        }
        else if(s[i]=='Y')
        {

            yp.push_back(i);

        }
    }

    int ck=kp.size();

    int ce=ep.size();

    int cy=yp.size();



    dp[0][0][0][0]=1;


    for(int i=0; i<n; i++)
    {
        for(int e=0; e<=ce; e++)
        {
            for(int y=0; y<=cy; y++)
            {
                int kk=i-e-y;


                if(kk<0||kk>ck)
                    continue;



                for(int st=0; st<=K; st++)
                {
                    if(!dp[i][e][y][st])
                        continue;



                    if (kk < ck)
                    {
                        int moveSteps = 0; // 把i+1位置的K往左交换
                        for (int l = 0; l < e; l++) if (ep[l] > kp[kk]) moveSteps++;
                        for (int l = 0; l < y; l++) if (yp[l] > kp[kk]) moveSteps++;

                        if (st + moveSteps <= K) dp[i + 1][e][y][st + moveSteps] += dp[i][e][y][st];
                    }

                    if (e < ce)
                    {
                        int moveSteps = 0;
                        for (int l = 0; l < kk; l++) if (kp[l] > ep[e]) moveSteps++;
                        for (int l = 0; l < y; l++) if (yp[l] > ep[e]) moveSteps++;

                        if (st + moveSteps <= K) dp[i + 1][e + 1][y][st+ moveSteps] += dp[i][e][y][st];
                    }

                    if (y < cy)
                    {
                        int moveSteps = 0;
                        for (int l = 0; l < kk; l++) if (kp[l] > yp[y]) moveSteps++;
                        for (int l = 0; l < e; l++) if (ep[l] > yp[y]) moveSteps++;

                        if (st+ moveSteps <= K) dp[i + 1][e][y + 1][st+ moveSteps] += dp[i][e][y][st];
                    }

                }
            }
        }
    }

    //  EKEY

  //  cout<<dp[][2][0][0]<<" "<<dp[2][2][0][1]<<" "<<dp[2][2][0][2]<<endl;


    ll res = 0;

    for (int i = 0; i <= K; i++) res+= dp[n][ce][cy][i];

    cout << res << endl;



    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qinsanma and Code

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值