2018 nowcoder 多校 10

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lingzidong/article/details/81880600

jls 第一场 真的不会场……
补题进度 【3/10】;场上 2
A Rikka with Lowbit
这道题的意思就是给一个数进行加它的lowbit或者减lowbit操作,这两个操作各有1/2的概率,问一个区间的区间和的期望。
以为有什么公式,结果手算了样例,发现样例中每次查询的值不变是真的。
所以就变成普通区间求和了。因为概率均等,加减的值都一样,所以加在一起就没了……

#include<cstring>
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
long long pow_mod(long long a,long long n,long long m)//a^n mod m
{
    long long res=1;
    while(n>0)
    {
        if(n&1==1)
            res=res*a%m;
        a=a*a%m;
        n>>=1;
    }
    return res;
}
//记得在最后输出结果的时候再模m一次
int a[100010];
ll sum[100010];
int main()
{
    //freopen("input.txt","r",stdin);
    int T;
    scanf("%d",&T);
    int opt,l,r;
    ll n,m;
    while(T--)
    {
        scanf("%lld%lld",&n,&m);
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&opt,&l,&r);
            if(opt==1)continue;
            ll ans=(sum[r]-sum[l-1])%mod*pow_mod(2,n*m,mod);
            ans%=mod;
            printf("%lld\n",ans);
        }
    }
    return 0;
}

J Rikka with Nickname
问的是将字符串顺次拼接,在前面的串不变,在后面的串只要是新串的子序列就行,求最小字典序的拼接结果。
一开始以为是什么后缀数组,结果仔细看了眼数据范围,就写了个暴力……
其实只要每次保存一下每个字符出现的位置,然后对于新串的从前往后的字符,找到一个存在的位置,找不到就把剩下的字符添加到最后面。
查找的过程可以二分一下。

#include <bits/stdc++.h>
#include  <cstring>
using namespace std;
const int MAXN = 1e6 + 5;
vector<int> pos[30];
char str[MAXN],tmp[MAXN];
typedef vector<int>::iterator vit;
int main()
{
    int ca;
    scanf("%d",&ca);
    while(ca--)
    {
        int n;
        memset(str,0,sizeof(str));
        for(int  i = 0; i<30; i++)
            pos[i].clear();
        scanf("%d",&n);
        scanf("%s",str);

        int tot = strlen(str);
        for(int i = 0; i<tot; i++)
        {
            pos[str[i] - 'a'].push_back(i);
        }
        for(int j = 0; j<n-1; j++)
        {
            scanf("%s",tmp);
            int len = strlen(tmp);
            int pre = -1;
            int i;
            bool flag = 1;
            for(i = 0; i<len; i++)
            {
                int id = tmp[i] - 'a';
                if(!pos[id].empty())
                {
                    //cout<<pre<<' ';
                    if(pre == -1)
                        pre = pos[id][0];
                    else
                    {
                        vit cur = upper_bound(pos[id].begin(),pos[id].end(),pre);
                        //cout<<*cur<<' ';
                        if(cur != pos[id].end())
                        {
                            pre = *cur;
                        }
                        else
                        {
                            flag = 0;
                            break;
                        }
                    }
                    //cout<<pre<<endl;
                }
                else
                {
                    flag = 0;
                    break;
                }
            }
            if(!flag)
            {
                for(int j = i; j<len; j++)
                {
                    str[tot] = tmp[j];
                    pos[tmp[j]-'a'].push_back(tot++);
                }
                //cout<<str<<endl;
            }
        }
        printf("%s\n",str);
    }
    return 0;
}

ps:我居然再通知改数据的一瞬间A了,但是之前交的都没过。感觉是C++哪里不兼容
D Rikka with Prefix Sum
题意很简单,就是没有搞出来。
这个其实将前缀和转化成组合数计算,然后根据每次求和操作建立时间戳。
这道题和9的一道题有点类似,由于没有出那道题,这道题也没想明白。
看样子需要写个单独的文章学习一下。

#include<bits/stdc++.h>
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
#define ll long long
#define all(a) a.begin(),a.end()
#define endl '\n'
using namespace std;
const int maxn = 2e5 + 1;
const ll mod = 998244353;
ll inv[maxn],fac[maxn];
void init()
{
    inv[0]=fac[0]=1;
    inv[1]=1;
    for(int i=1; i<maxn; i++)
        fac[i]=fac[i-1]*i%mod;
    inv[1]=1;
    for(int i=2; i<maxn; i++)
        inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
    inv[0]=1;
    for(int i=1; i<maxn; i++)
        inv[i]=inv[i-1]*inv[i]%mod;
}
ll com(int n,int m)
{
    if(m > n || n< 0 || m < 0) return 0;
    return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
ll pow_mod(ll a,ll n)
{
    ll res = 1,b = a % mod;
    while(n)
    {
        if(n & 1)
            res = res * b % mod;
        b = b *b % mod;
        n >>= 1;
    }
    return res;
}
struct Query
{
    int l,d,v;
};
vector<Query> Q;
int main()
{
    init();
    int ca;
    scanf("%d",&ca);
    while(ca--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        int op,l,r,v;
        int cnt= 0;
        Q.clear();
        for(int i = 0; i<m; i++)
        {
            scanf("%d",&op);
            if(op == 1)
            {
                scanf("%d%d%d",&l,&r,&v);
                Q.pb({l,cnt-1,v});
                Q.pb({r+1,cnt-1,-v});
            }
            else if(op == 2)
                cnt++;
            else
            {
                scanf("%d%d",&l,&r);
                ll ans = 0,tmp;
                for(auto &q : Q)
                {
                    tmp = cnt - q.d;
                    if(q.l <= l-1)
                    {
                        ans = (ans - q.v *com(l - q.l + tmp -1,l - q.l -1) % mod + mod) % mod;
                        ans = (ans % mod + mod)% mod;
                    }
                    if(q.l <= r)
                    {
                        ans = ( ans + q.v * com(r - q.l + tmp,r - q.l) % mod + mod) % mod;
                        ans = (ans % mod + mod) % mod;
                    }
                }
                printf("%lld\n",ans % mod);
            }

        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lingzidong/article/details/81880600