cf特训 #1(思维C两题)

C. String Equality

题意

  • 给定长度为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++) {//遍历考虑a~y
      //若a的字符比b的少则直接不能匹配,或者a多但多的不是k的倍数则不能进行操作二。那么匹配失败
        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;
}

C. Random Events

题意

  • 给定一个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--)//找最后一个没排好序的位置last
        if(a[i]!=i) {
            last=i;
            break;
        }
    
    int r;
    double p,ans=1;//无序的概率为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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值