E - Swap Editorial
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : 500500 points
Problem Statement
Given is a string SS consisting of K
, E
, Y
.
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
K
,E
,Y
.
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: KEY
, EKY
, KYE
.
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: KKEE
, KEKE
, EKKE
, KEEK
.
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;
}