牛客网暑期ACM多校训练营(第十场)[题解]

A     Rikka with Lowbit

题目:有两个操作,一个就是将A_{i}变为f(A_{i}) ,二是求一个区间和的期望;

题解:可以看出就是一个区间和就可以啦。

代码:

#include
#define ll long long
 
using namespace std;
const ll mod = 998244353;
const int maxn = 1e5+7;
 
ll qpow(ll a, ll b) {
    ll ans = 1ll;
    while(b) {
        if(b&1) ans = ans*a%mod;
        a = a*a%mod;
        b>>=1;
    }
    return ans;
}
 
ll a[maxn];
 
int main()
{
    int t; scanf("%d", &t);
    while(t--) {
        ll n, m; scanf("%lld%lld", &n, &m);
        ll A, B = qpow(2ll, n*m);
        for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
        for(int i = 1; i <= n; i++) a[i] = (a[i]+ a[i-1])%mod;
        for(int i = 0; i < m; i++) {
            int t, l, r; scanf("%d%d%d", &t, &l, &r);
            if(t==1) continue;
            else {
                A = (a[r] - a[l-1] + mod)%mod;
                printf("%lld\n", A*B%mod);
            }
        }
    }
    return 0;
}

B     Rikka with Burrow-Wheeler Transform

 

C     Rikka with Rotate

 

D     Rikka with Prefix Sum

题意:给一个数组a,一开始的值全为0,一共有三个操作: 
1. 对区间[L,R]的每个数都加上w。 
2. 将数组a用其前缀和数组代替。 
3. 将询问区间[L,R]的区间和。

题解:假设初始状态是t = 0,每执行一次 2 就t++,这样考虑每个1操作对于后面的影响,考虑是路径的问题,就是组合数。

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define ll long long
 
using namespace std;
 
const ll maxn = 5e6+7;
const ll mod = 998244353;
 
struct node{
    ll t, where, w;
} A[maxn];
 
int len;
ll F[maxn + 10], inv[maxn + 10];
 
ll qpow(ll a, ll b){
    ll ans = 1ll;
    while(b){
        if(b&1) ans = (ans*a)%mod;
        a = (a*a)%mod;
        b >>= 1;
    }
    return ans;
}
 
void init()
{
    F[0] = 1ll;
    for (ll i = 1; i <= maxn; i++) F[i] = (F[i-1]*i)%mod;
    inv[maxn] = qpow(F[maxn], mod - 2ll); //费马小定理求 N!的逆元
    for(ll i = maxn - 1; i >= 0; i--) inv[i] = (inv[i+1]*(i+1))%mod;
}
 
 
ll C(ll a , ll b){ return F[a]*inv[b]%mod*inv[a-b]%mod; }
 
ll query(ll where,ll t){
    ll ans = 0;
    for (int i = 1; i <= len; i++)
        if (A[i].where <= where) ans = (ans + A[i].w*C(where - A[i].where + t - A[i].t - 1, t - A[i].t - 1))%mod;
    return ans;
}
 
void solve(){
    int n, m;
    scanf("%d%d", &n, &m);
    len = 0;
    ll t = 0, l, r, w;
 
    while(m--){
        int op; scanf("%d", &op);
        if(op == 1){
            scanf("%lld%lld%lld", &l, &r, &w);
            A[++len] = (node){ t-1, l, w };
            A[++len] = (node){ t-1, r+1, (mod-w)%mod };
        } else if (op == 2) t++;
          else{
            scanf("%lld%lld", &l, &r);
            printf("%lld\n",(query(r, t+1) - query(l-1, t+1) + mod)%mod);
        }
    }
}
 
 
 
int main(){
    init();
    //freopen("in.txt", "r", stdin);
    int t;
    scanf("%d", &t);
    while(t--) solve();
    return 0;
}

E     Rikka with Equation

题意:一组系数A,模数m ,定义f(A_{i}, m)为模线性方程\sum a_{i}*x_{i}\equiv 0\ (mod \ m)的解数给出一个长度为n的数组B,对于B的所有非空子集Am\in [1,M]w_{m} = \sum f(A_{i}, m) \ mod \998244353,求所有w_{m}的异或和。(n,m,B_{i} \leqslant 10^{5})

题解:证明f(A_{i}, m) = gcd(A_{i}, m)*m^{|A_{i}| - 1},考虑中国剩余定理,将m质因子分解成p_{1}^{t_{1}}p_{2}^{t_{2}}p_{i}^{t_{i}},考虑在每个p_{i}^{t_{i}}下解的个数,总的解的个数就是各个结果的乘积;

因为p_{i}是质数,因此\sum a_{i}*x_{i}\equiv 0\ (mod \ p_{i}^{t_{i}}),其中a_{i}p_{i}互质的部分可以用其相对于p_{i}逆元合并到x_{i}中,则方程改写为\sum p_{i}^{q_{i}}*x_{i}\equiv 0\ (mod \ p_{i}^{t_{i}}),我们假设p_{i}^{q_{i}}中最小的是p_{i}^{q_{1}},其他的部分看作C,故方程是p_{i}^{q_{1}}*x_{1} + C \equiv 0 \ (mod \ q_{i}^{t_{i}}),所以方程有解的情况是gcd(p_{i}^{q_{1}}, p_{i}^{t_{i}})|C,因为p_{i}^{q_{1}}是最小的一个,故C能够整除p_{i}^{q_{1}},且解数共有p_{i}^{q_{1}}个(WK),剩下的x的值可以随便取有p_{i}^{t_{i}}种取值(题目中x_{i}\in [0, m),所以在模p_{i}^{t_{i}}下有p_{i}^{q_{1}}*(p_{i}^{t_{i}})^{|A| - 1}种取值,我们合并一下答案就是f(A_{i}, m) = gcd(A_{i}, m)*m^{|A_{i}| - 1},先写到这里,暂时留坑。

 

F     Rikka with Line Graph

 

G     Rikka with Shortest Path

 

H     Rikka with Ants

 

I      Rikka with Zombies

 

J     Rikka with Nickname

分析:直接模拟吧。。。

代码:

#include
using namespace std;
 
string ans, s, t;
 
int main()
{
    int T;
    scanf("%d", &T);
    while(T--) {
        int n;
        scanf("%d", &n);
        cin >> ans; n--;
        while(n--) {
            cin >> s;
            int i = 0, j = 0;
            for(; i < ans.length()&&j < s.length(); i++) {
                if(ans[i] == s[j]) j++;
            }
            for(; j < s.length(); j++) ans += s[j];
        }
        cout << ans << endl;
    }
    return 0;
}

 

你可能感兴趣的:(2018,牛客网ACM多校训练营)