总结:
今天这把多校,一开始签了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(1≤i≤n) ,问有多少个区间满足区间内的数字种数为 m m m
做法:
双指针,维护左右区间内数字的种数,若 l , r l,r l,r 区间内数字种数为 m m m ,则对答案的贡献为 n − r + 1 n-r+1 n−r+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 n≤100
做法:
使用二进制构造的方法,例如 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;
}