zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:stone(结论+桶+前缀和+差分)

    题目描述

    $Cab$有两行石子,每个石子上有一个字母,为$'C''A''B'$中的一个。
    一开始,在每行第一个石子上站着一只$lucky$,$Cab$每次可以选择一个字母,使得所站石子上字母为该字母的$lucky$向前走一步,如果此时$lucky$已经到了一行石子的结尾就会掉出去,$Cab$显然不会这么做。
    一个数对$(x,y)$是$lucky$的,当且仅当在$lucky$不掉出去的前提下,通过一些操作能使第一行的$lucky$处于第$x$个石子的同时第二只$lucky$处于第$y$个石子。
    请求出有多少个$lucky$的数对。


    输入格式

    第一行一个长度为$n$的字符串表示第一行石子。
    第二行一个长度为$m$的字符串表示第二行石子。


    输出格式

    输出一个答案表示$lucky$的数对个数。


    样例

    样例输入:

    CAB
    ABCAB

    样例输出:

    11


    数据范围与提示

    对于$30\%$的数据:$nleqslant 1,000,mleqslant 1,000$。
    对于另$30\%$的数据:$nleqslant 50,000,mleqslant 50,000$,且两个字符串中只含有两种字母。
    对于$100\%$的数据:$nleqslant 1,000,000,mleqslant 1,000,000$。


    题解

    官方题解画了一堆图,我也没看懂。

    对于第一个串中的每一个点,其有一个覆盖范围$(l,r)$,可以用贪心的思想,$l$即为尽可能让其不动;$r$则为尽可能让它动;注意边界即可。

    但是打个表会发现,这中间有一些点还是不能取到;再认真看一下,会发现对于当前点$a_i$,如果$a_i=b_j$且$a_{i-1}=b_{j+1}$,那么这个$(i,j)$是不可取的。

    那么答案就是:

    $$ans=sum limits_{i=1}^n r_i-l_i+1-num[i]$$

    上式中的$num[i]$即为$l_isim r_i$中$a_i=b_j$且$a_{i-1}=b_{j+1}$的个数。

    $num$数组可以用桶$+$前缀和$+$差分处理。

    如果你发现$WA90$的话可以考虑将两个串的读入顺序交换即可。

    时间复杂度:$Theta(n+m)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int a[1000001],b[1000001],la,lb;
    char ch1[1000001],ch2[1000001];
    int l[1000001],r[1000001];
    int t[1000001][6];
    long long ans;
    int main()
    {
    	scanf("%s%s",ch1+1,ch2+1);
    	la=strlen(ch2+1);
    	lb=strlen(ch1+1);
    	for(int i=1;i<=la;i++)
    		a[i]=ch2[i]-'A'+1;
    	for(int i=1;i<=lb;i++)
    		b[i]=ch1[i]-'A'+1;
    	int faill=1,failr=1;
    	for(int i=1;i<=la;i++)
    	{
    		while(a[i]!=b[failr]&&failr<lb)failr++;
    		l[i]=faill;r[i]=failr;
    		if(a[i]==b[faill]&&faill<lb)faill++;
    		if(failr<lb)failr++;
    	}
    	for(int i=2;i<=lb;i++)
    	{
    		if(b[i-1]==1&&b[i]==2)t[i][0]++;
    		if(b[i-1]==2&&b[i]==1)t[i][1]++;
    		if(b[i-1]==1&&b[i]==3)t[i][2]++;
    		if(b[i-1]==3&&b[i]==1)t[i][3]++;
    		if(b[i-1]==2&&b[i]==3)t[i][4]++;
    		if(b[i-1]==3&&b[i]==2)t[i][5]++;
    		t[i][0]+=t[i-1][0];
    		t[i][1]+=t[i-1][1];
    		t[i][2]+=t[i-1][2];
    		t[i][3]+=t[i-1][3];
    		t[i][4]+=t[i-1][4];
    		t[i][5]+=t[i-1][5];
    	}
    	ans=r[1]-l[1]+1;
    	for(int i=2;i<=la;i++)
    	{
    		ans+=r[i]-l[i]+1;
    		if(a[i]==a[i-1])continue;
    		if(a[i]==1&&a[i-1]==2)ans-=t[r[i]][0]-t[l[i]-1][0];
    		if(a[i]==2&&a[i-1]==1)ans-=t[r[i]][1]-t[l[i]-1][1];
    		if(a[i]==1&&a[i-1]==3)ans-=t[r[i]][2]-t[l[i]-1][2];
    		if(a[i]==3&&a[i-1]==1)ans-=t[r[i]][3]-t[l[i]-1][3];
    		if(a[i]==2&&a[i-1]==3)ans-=t[r[i]][4]-t[l[i]-1][4];
    		if(a[i]==3&&a[i-1]==2)ans-=t[r[i]][5]-t[l[i]-1][5];
    	}
    	printf("%lld",ans);
    	return 0;	
    }
    

    rp++

  • 相关阅读:
    racle SQL性能优化
    Oracle 删除重复数据只留一条
    oracle存储过程常用技巧
    详解:数据库名、实例名、ORACLE_SID、数据库域名、全局数据库名、服务名及手工脚本创建oracle数据库
    用友ERP-U8最新破解(再次更新版本,附安装过程中的解决办法)
    轻松三步教你配置Oracle—windows环境
    非常好的Oracle教程【转】
    Oracle新表使用序列(sequence)作为插入值,初始值不是第一个,oraclesequence
    大数据学习资源汇总
    Index
  • 原文地址:https://www.cnblogs.com/wzc521/p/11743867.html
Copyright © 2011-2022 走看看