CF674DIV3-总结

2023大厂真题提交网址(含题解):

www.CodeFun2000.com(http://101.43.147.120/)

最近我们一直在将收集到的机试真题制作数据并搬运到自己的OJ上,供大家免费练习,体会真题难度。现在OJ已录入50+道2023年最新大厂真题,同时在不断的更新。同时,可以关注"塔子哥学算法"公众号获得每道题的题解。
在这里插入图片描述
前言:一天独立AK两场DIV3就离谱。。造成了一种我没那么垃圾的假想.

E.思维.数学
题目大意:

石头剪刀布.已知Alice会分别会出 a , b , c a,b,c a,b,c次,已知Bob会求出 x , y , z x,y,z x,y,z次。但是顺序不确定。现在让你安排顺序使得Alice 赢得最多/赢得最少.

n ≤ 1 e 9 , a + b + c = x + y + z = n n\leq 1e9 , a+b+c=x+y+z=n n1e9,a+b+c=x+y+z=n

题目思路:

一.赢得最多很容易,贪心的算即可: m i n ( a , y ) + m i n ( b , z ) + m i n ( c , x ) min(a,y)+min(b,z)+min(c,x) min(a,y)+min(b,z)+min(c,x)即可.

二.赢得最少,考虑简单的鸽巢原理:

1.当 a + y > n a+y > n a+y>n时,无论怎么安排这个场次,一定会有 a + y − n a+y-n a+yn场Alice会赢.
2.当 b + z > n b+z > n b+z>n时,无论怎么安排这个场次,一定会有 b + z − n b+z-n b+zn场Alice会赢.
3.当 c + x > n c+x > n c+x>n时,无论怎么安排这个场次,一定会有 c + x − n c+x-n c+xn场Alice会赢.

并且上述三者只会同时成立一个。因为若有两个成立,那么它们的和 > 2 n >2n >2n.与题目违背.

那么显然答案就是三者之间的最大值: m a x ( 0 , m a x ( a + y − n , m a x ( b + z − n , c + x − n ) ) ) max(0,max(a+y-n,max(b+z-n,c+x-n))) max(0,max(a+yn,max(b+zn,c+xn)))

遗留问题:如何证明若三者同时不成立则一定不会有冲突。并且找出一种合法的不冲突构造方案.

F.计数dp
题目大意:

给你一个只含 a , b , c , ? a,b,c,? a,b,c,?的字符串. ? 可填写 a , b , c ?可填写a,b,c ?可填写a,b,c.现在问你对于所有可能的字符串,它们中总共含有多少个子序列 a b c abc abc.

n ≤ 2 e 5 n \leq 2e5 n2e5

题目思路:

考虑没有问号的情况:令 d p ( i , j ) dp(i,j) dp(i,j)代表前i个字符,有多少个子序列 r e s [ 1 → j ] res[1\rightarrow j] res[1j], r e s = " a b c " res="abc" res="abc".

现在有问号加进来了,那么将状态升维,令 d p ( i , j , k ) dp(i,j,k) dp(i,j,k)代表前i个字符,且当前这个位置填写 ′ a ′ + j 'a'+j a+j,有多少个子序列 r e s [ 1 → j ] res[1\rightarrow j] res[1j], r e s = " a b c " res="abc" res="abc".

转移的时候多层循环即可。有个转移的细节是:

当当前位置填写a的时候,他这个位置对 [子序列’a’] 的个数的贡献应
该是: 3 x 3^x 3x.而不仅仅是 1 1 1.(x代表这个位置之前 ? ? ? 的个数).

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
const int maxn = 2e5 + 5;
const int mod = 1e9 + 7;
ll a[maxn];
ll dp[maxn][4][4];
int main()
{
    ios::sync_with_stdio(false);
    int t; t = 1;
    while (t--){
        ll n ; cin >> n;
        string a; cin >> a;
        a = '#' + a;
        ll cnt = 1;
        for (int i = 1 ; i <= n ; i++){
            if (a[i] == '?') {
                for (int e = 1 ; e <= 3 ; e++)
                    for (int j = 1 ; j <= 3 ; j++)
                        for (int k = 1 ; k <= 3 ; k++)
                            dp[i][e][j] = (dp[i][e][j] + dp[i - 1][k][j])%mod;
                dp[i][1][1] = (dp[i][1][1] + cnt) % mod;
                for (int j = 1 ; j <= 3 ; j++)
                    dp[i][2][2] = (dp[i][2][2] + dp[i - 1][j][1])%mod ,
                    dp[i][3][3] = (dp[i][3][3] + dp[i - 1][j][2])%mod;
                cnt *= 3ll;
                cnt %= mod;
            }
            else{
                int v = a[i] - 'a' + 1;
                for (int j = 1 ; j <= 3 ; j++)
                    for (int k = 1 ; k <= 3 ; k++)
                        dp[i][v][j] = (dp[i][v][j] + dp[i - 1][k][j])%mod;
                if (v == 1) dp[i][v][1] = (dp[i][v][1] + cnt) % mod;
                else if (v == 2) {
                    for (int j = 1 ; j <= 3 ; j++)
                        dp[i][v][2] = (dp[i][v][2] + dp[i - 1][j][1])%mod;
                }
                else {
                    for (int j = 1 ; j <= 3 ; j++)
                        dp[i][v][3] = (dp[i][v][3] + dp[i - 1][j][2])%mod;
                }
            }
        }
        int ans = 0;
        for (int i = 1 ; i <= 3 ; i++){
            ans = (ans + dp[n][i][3])%mod;
        }
        cout << ans << endl;
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值