AtCoder Beginner Contest 232(E,F补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AtCoder Beginner Contest 232(E,F补题)相关的知识,希望对你有一定的参考价值。

E - Rook Path

题意:

给定大小为 H × W H×W H×W的矩阵,你现在有一个车(在矩阵可以朝着一个方向走任意距离),现在起点为 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),终点 ( x 2 , y 2 ) (x_2,y_2) (x2,y2),你现在只可以恰好移动 k k k次,问从起点移动到终点的方案数为多少?

思路:

对于横和纵分别定义一个 d p dp dp方程,把一个二维的移动看成两个一维的移动,分别定义为 X ( i , 0 / 1 ) , Y ( i , 0 / 1 ) X(i,0/1),Y(i,0/1) X(i,0/1),Y(i,0/1)
X ( i , 0 / 1 ) X(i,0/1) X(i,0/1)为例,代表移动了 i i i次后,是否到达了终点的方案数(只考虑 x x x轴), 0 0 0代表未到达, 1 1 1代表到达了
那么此时状态转移方程
X ( i , 1 ) = X ( i − 1 , 0 ) X(i,1)=X(i-1,0) X(i,1)=X(i1,0)
X ( i , 0 ) = X ( i − 1 , 0 ) × ( n − 2 ) + X ( i − 1 , 1 ) × ( n − 1 ) X(i,0)=X(i-1,0)×(n-2)+X(i-1,1)×(n-1) X(i,0)=X(i1,0)×(n2)+X(i1,1)×(n1)
Y Y Y同理
最后就是遍历所有的 X ( i , 1 ) 和 Y ( k − i , 1 ) X(i,1)和Y(k-i,1) X(i,1)Y(ki,1),把两个一维的方案相乘,再乘上一个组合数 C k i C^i_k Cki,来确定这两个一维方案的移动顺序

#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
const int mod = 998244353;
#define ll long long
int n, m, k, X1, Y1, X2, Y2;
ll x[N][2], y[N][2], fact[N], infact[N];
ll qmi(int a, int k, int p) 
    ll res = 1;
    while (k) 
        if (k & 1) res = (ll)res * a % p;
        k >>= 1;
        a = (ll)a * a % p;
    
    return res;

void Init() 
    fact[0] = infact[0] = 1;
    for (int i = 1; i < N; i++) 
        fact[i] = (ll)fact[i - 1] * i % mod;
        infact[i] = (ll)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
    


ll C(int a, int b) 
    if (a < b) return 0;
    return fact[a] * infact[b] % mod * infact[a - b] % mod;


int main() 
    Init();
    scanf("%d%d%d", &n, &m, &k);
    scanf("%d%d%d%d", &X1, &Y1, &X2, &Y2);

    if (X1 != X2) 
        x[0][0] = 1;
     else 
        x[0][1] = 1;
    
    if (Y1 != Y2) 
        y[0][0] = 1;
     else 
        y[0][1] = 1;
    
    for (int i = 1; i <= k; i++) 
        (x[i][1] += x[i - 1][0]) %= mod;
        x[i][0] += (x[i - 1][1] * (n - 1) % mod + x[i - 1][0] * (n - 2) % mod) % mod;
        x[i][0] %= mod;

        (y[i][1] += y[i - 1][0]) %= mod;
        y[i][0] += (y[i - 1][1] * (m - 1) % mod + y[i - 1][0] * (m - 2) % mod) % mod;
        y[i][0] %= mod;
    

    ll res = 0;

    for (int i = 0; i <= k; i++) 
        ll temp = x[i][1] * y[k - i][1] % mod;
        res += temp * C(k, i) % mod;
        res %= mod;
    
    printf("%lld\\n", res);

F - Simple Operations on Sequence

题意:

给定两个长度为 N N N A A A序列和 B B B序列,现在有 2 2 2种操作
1. 1. 1.使得 A i A_i Ai增加 1 1 1或者减少 1 1 1,需要消耗 X X X
2. 2. 2.交换 A i A_i Ai A i + 1 A_i+1 Ai+1的位置,需要消耗 Y Y Y
可以操作多次,问最少花费多少才能使 A A A序列变成 B B B序列

思路:

序列长度很小,仅为 18 18 18,所以可以考虑状态压缩
假设现在 A A A序列中的数有 i i i个已经确定,变成 B B B中的前 i i i个,当然也可以倒过来,是等效的。
那么现在如何表示 A A A中哪 i i i个数已经确定下来了,就是通过二进制,也就是状态压缩,通过二进制中的 1 1 1的位置,来表示哪些数已经被确定下来了。那么此时只需要枚举,接下来确定那个数即可,且这个数在当前状态下不能被确定过,此时枚举的就是第 i + 1 i+1 i+1个数,那么此时的代价就是 ∣ A [ i + 1 ] − B [ j ] ∣ × X + c n t × Y |A[i+1]-B[j]|×X+cnt×Y A[i+1]B[j]×X+cnt×Y c n t cnt cnt就是把 B j B_j Bj移动到 A i + 1 A_i+1 Ai+1位置所需要交换的次数。
所以假设状态就是 s t a t e state state, c n t S cntS cntS为确定数的个数,枚举的数是 B j B_j Bj c n t cnt cnt是把
f ( s t a t e ∣ 1 < < ( j − 1 ) ) = m i n ( f ( s t a t e ∣ 1 < < ( j − 1 ) ) , f ( s t a t e ) + ∣ A [ i + 1 ] − B [ j ] ∣ × X + c n t × Y ) f(state|1<<(j-1))=min(f(state|1<<(j-1)),f(state)+|A[i+1]-B[j]|×X+cnt×Y) f(state1<<(j1))=min(f(state1<<(j1)),f(state)+A[i+1]B[j]×AtCoder Beginner Contest 234

AtCoder Beginner Contest 115 题解

AtCoder Beginner Contest 154 题解

AtCoder Beginner Contest 103

AtCoder Beginner Contest 228

AtCoder Beginner Contest 242