2022牛客暑期多校训练营9(总结+补题)

总结:

今天这把多校,一开始签了A之后,发现G是个回文自动机的简单题,我去学了一个小时之后把这道题A了,队友1也学了一个多小时后把B的概率dp A了,接下来就来到了罚坐时间,队友2看一直没什么人做的C但是没写出来,最后大家一起写E,写到最后发现题读假了,3题结束。

题解

A - Car Show

题意:

给你一个由 m m m 种数组成的序列 a i ( 1 ≤ i ≤ n ) a_i(1\le i\le n) ai(1in) ,问有多少个区间满足区间内的数字种数为 m m m

做法:

双指针,维护左右区间内数字的种数,若 l , r l,r l,r 区间内数字种数为 m m m ,则对答案的贡献为 n − r + 1 n-r+1 nr+1

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n,m,k;
const int maxn =100010;
int a[maxn],vis[maxn];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    int l=1,r=0;
    int num=0;
    int ans=0;
    while(1)
    {
        while(num<m&&r<n)
        {
            r++;
            if(!vis[a[r]])
                num++;
            vis[a[r]]++;
        }
        if(num!=m)
            break;
        while(num==m)
        {
            ans+=n-r+1;
            if(vis[a[l]]==1)
                num--;
            vis[a[l++]]--;
        }
    }
    cout<<ans<<endl;
    return 0;
}

G - Magic Spells

题意:

给你 k k k 个字符串,问这 k k k 个字符串中本质不同的公共回文字符串有多少种

做法:

考虑使用回文自动机来解决问题,我们知道回文自动机中的每个状态都表示了单独的一个字符串的回文子串,我们可以对 k k k 个字符串建回文自动机,然后同时对他们进行 d f s dfs dfs ,若能同时更新状态,则答案 +1并继续往下搜,反之则停止搜索。

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n,m,k;
struct PAM{
    int sz,tot,last;
    string ss;
    struct node{
        int cnt = 0,fail = 0,len;
        // unordered_map<char,int> ch;
        array<int,26> ch;
    };
    vector<node> st;
    int node(int l)
    {
        sz++;
        st.emplace_back();
        st[sz].len = l;
        // memset(st[sz].ch,0,sizeof st[sz].ch);
        return sz;
    }
    void init()
    {
        sz = -1;
        last = 0;
        tot = 0 ;
        ss='$';
        node(0);
        node(-1);
        st[0].fail = 1;
    }
    int getfail(int x)
    {
        while(ss[tot - st[x].len - 1] != ss[tot])
            x = st[x].fail;
        return x;
    }
    void insert(char c)
    {
        ss += c;
        tot++;
        int now = getfail(last);
        if(!st[now].ch[c-'a'])
        {
            int x = node(st[now].len + 2);
            st[x].fail = st[getfail(st[now].fail)].ch[c-'a'];
            st[now].ch[c-'a'] = x;
        }
        last = st[now].ch[c-'a'];
        st[last].cnt++;
    }
};
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>k;
    string ss;
    PAM p[k];
    for(int i=0;i<k;i++)//输入字符串、建自动机
    {
        cin>>ss;
        p[i].init();
        for(auto c:ss)
            p[i].insert(c);
    }
    vector<int> a(k,0),b(k,1);
    int ans=0;
    function<void(vector<int>&)> dfs = [&](vector<int> &idx)
    {
        for(int i=0;i<26;i++)
        {
            int flag=1;
            vector<int> f1(k,0);
            for(int j=0;j<k;j++)
            {
                f1[j]=p[j].st[idx[j]].ch[i];
                flag&=(bool)f1[j];
            }
            if(flag)
            {
                ans++;
                dfs(f1);
            }
        }
    };
    dfs(a);//偶数长度回文串
    dfs(b);//奇数长度回文串
    cout<<ans<<endl;
    return 0;
}

E - Longest Increasing Subsequence

题意:

构造一个长度为 n n n 的排列,满足排列中最长上升子序列的个数为 m m m n ≤ 100 n\le100 n100

做法:

使用二进制构造的方法,例如 2143657 2143657 2143657 2 3 = 8 2^3=8 23=8 个, 5216437 5 2 1 6 4 3 7 5216437 2 2 + 2 1 + 2 0 = 7 2^2+2^1+2^0=7 22+21+20=7

代码:

/*
 author:wuzx
 */

#include<bits/stdc++.h>
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
typedef unsigned long long ull;
const int maxn = 200010;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
int t;
int n,m,k;
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin>>t;
    while(t--)
    {
        cin>>n;
        vector<int> a;
        while(n)
        {
            if(n&1)
                a.emplace_back(1);
            else
                a.emplace_back(0);
            n/=2;
        }
        int sz=a.size();
        vector<int> ans;
        for(int i=1;i<=sz-1;i++)
        {
            ans.emplace_back(i*2);
            ans.emplace_back(i*2-1);
        }
        int num=1,ma=sz*2-1;
        ans.emplace_back(-1);
        for(int i=sz-1;i>=0;i--)
        {
            if(a[i]==1)
            {
                int pos=i*2;
                int nb=sz-i-num;
                for(int j=0;j<nb;j++)
                    ans.insert(ans.begin()+pos,-1);
                num+=nb;
            }
        }
        for(auto &x:ans)
            if(x==-1)
                x=ma++;
        cout<<ans.size()<<endl;
        for(int x:ans)
            cout<<x<<" ";
        cout<<endl;
    }   
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值