231114校内模拟赛
T1 平凡
首先,我们容易发现直接求 \(A\) 不是最小的子序列的排列的个数有些困难
那我们转换一下来求是最小的子序列的个数再用总个数减去便是合法个数
首先总个数很容易求出,就是 \(\frac{n!}{m!}\)
再考虑不合法个数
性质一:对于每一个 \(A_i\) 前面都不可能有比他小的数出现,否则就可以替换掉当前数
性质二:如果一个数前面已经有了一个大的数,那么这个数就是排列的后缀上的,否则仍然能够替换掉当前数使得字典序更小
于是我们找到单调递增的最长前缀,这个以后的部分就一定是排列的一个后缀
然后对于每一个没有出现的数,从小到大一次插入,根据性质一,我们可以判断有多少个空可以插入
然后按乘法原理处理即可
#include<bits/stdc++.h>
#define mod 998244353
#define N 1000010
#define int long long
using namespace std;
int n,k,a[N],t[N],vis[N],ans,all,pos;
signed main(){
freopen("ordinary.in","r",stdin);
freopen("ordinary.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k;
ans = all = 1;
for(int i = k+1;i<=n;i++)
all = all*i%mod;
for(int i = 1;i<=k;i++){
cin>>a[i];
t[a[i]] = 1;
}
for(int i = 1;i<=k;i++){
if(a[i]>a[i+1]){
pos = i;
for(int j = i+1;j<=k;j++)
vis[a[j]] = 1;
break;
}
}
int sum = 0;
for(int i = 1;i<=n;i++){
if(!vis[i]){
if(!t[i])
ans = ans*(sum+(i>a[pos]))%mod;
sum++;
}
}
cout<<(all-ans+mod)%mod;
return 0;
}
T2 奇迹
洛谷题解讲的很明白了,不过代码实现上不够清楚
对于 \(pre\) 函数就是处理出了每一个括号配对的位置
\(getans\) 函数就是就是题解中所说的 \(f,g\) 两个数组,对于 \(flag\) 就是判断到底当前是哪种序列
\(dfs\) 函数就是对于每一个区间递归计算答案,先处理出哪些左括号是当前层的左括号
然后比较两个字符串是否相同,当前层相同则不操作,否则计算答案,最后还原数组
#include<bits/stdc++.h>
#define N 1000010
using namespace std;
int n,ans,apair[N],bpair[N],aleft[N],bleft[N];
char a[N],b[N];
inline void pre(char s[],int t[]){
stack<int>stk;
for(int i = 1;i<=n;i++){
if(s[i]==')'){
t[i] = stk.top();
t[t[i]] = i;
stk.pop();
}else stk.push(i);
}
}
int getans(int t[],int l,int r,bool flag){
if(l+1==r) return 0;
if(t[l+1]==r-1){
if(!flag) return getans(t,l+1,r-1,1)+1;
return getans(t,l+1,r-1,1);
}else{
int res = 0;
for(int i = l+1;i<r;i = t[i]+1)
res+=getans(t,i,t[i],0);
return res+(flag?1:2);
}
}
int dfs(int l,int r){
if(l+1==r) return 0;
int res = 0;
for(int i = l;i<=r;i = apair[i]+1) aleft[i] = 1;
for(int i = l;i<=r;i = bpair[i]+1) bleft[i] = 1;
for(int i = l;i<=r;i = apair[i]+1)
if(bleft[i]&&apair[i]==bpair[i])
res+=dfs(i+1,apair[i]-1);
for(int i = l;i<=r;i = apair[i]+1)
if(!bleft[i]||apair[i]!=bpair[i])
res+=getans(apair,i,apair[i],0);
for(int i = l;i<=r;i = bpair[i]+1)
if(!aleft[i]||apair[i]!=bpair[i])
res+=getans(bpair,i,bpair[i],0);
for(int i = l;i<=r;i = apair[i]+1) aleft[i] = 0;
for(int i = l;i<=r;i = bpair[i]+1) bleft[i] = 0;
return res;
}
int main(){
freopen("miracle.in","r",stdin);
freopen("miracle.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>a+1>>b+1;
pre(a,apair);
pre(b,bpair);
cout<<dfs(1,n);
return 0;
}
梦与现实间挣扎着,所求为何
你可以借走我的文章,但你借不走我的智慧 虽然我是傻逼本文来自博客园,作者:cztq,转载请注明原文链接:https://www.cnblogs.com/cztq/p/17832236.html