题意
- 给定长度为n的两个字符串a,b,问能否通过任意次操作使得a变成b
- 操作:a字符串中的任意相邻的两字符可以互换位置;连续的k个相同的字符段可以变成后一个字符,如k=2,aa->bb。而若相同的字符段为z则不能转换
题解
- 由于任意相邻的字符可以互换位置,意味着可以任意重排字符串a,也就是说不需要考虑位置,只需要关注某种字符的数量即可
- 由上一条,我们可以把a,b都看做按顺序排列的字符串,那么数量相同的可以直接匹配掉,而对于不能匹配掉多出来的字符(a~y)则考虑操作二,k个k个的转换为下一个字符,那么此字符考虑完毕
代码
#include <iostream>
#include <cstring>
using namespace std;
const int N=1e6+10;
char a[N],b[N];
int suma[30],sumb[30];
bool solve() {
memset(suma,0,sizeof suma);memset(sumb,0,sizeof sumb);
int n,k;
cin>>n>>k>>a>>b;
for(int i=0;i<n;i++) {suma[a[i]-'a']++;sumb[b[i]-'a']++;}
for(int i=0;i<25;i++) {
if(suma[i]<sumb[i] || (suma[i]-sumb[i])%k) return false;
suma[i+1]+=suma[i]-sumb[i];
}
return true;
}
int main() {
int t;
cin>>t;
while(t--) cout<<(solve() ? "YES":"NO")<<'\n';
return 0;
}
题意
- 给定一个n的排列,以及一些操作(ri,pi),(r,p)代表把序列的前r位排好序的概率为p
- 问完全排好序的概率为多少
题解
- 从后往前看,最后一个没排好序的(a[i]!=i)位置last之前一定要排好才能使得完全排列好;意味着在last之后的操作r失败会使得排列没有排好序,因为last之前的r不论成功与否,a都无序;那么r>=last的操作失败时就一定导致a无序,所以统计得到使得a无序的概率为p,则答案为1-p
- 为什么用逆向思维?因为正面算排序成功的概率很复杂,而统计失败的概率简单,所以逆向思维
代码
#include <iostream>
#include <cstdio>
using namespace std;
const int N=1e5+10;
int a[N];
void solve() {
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
int last=0;
for(int i=n;i>=1;i--)
if(a[i]!=i) {
last=i;
break;
}
int r;
double p,ans=1;
while(m--) {
cin>>r>>p;
if(r>=last) ans*=(1-p);
}
printf("%.7lf\n",(last ? 1-ans:1));
}
int main() {
int t;
cin>>t;
while(t--) solve();
return 0;
}