CF1886D Monocarp and the Set

Link

此題目可以從兩個方向考慮,正着和倒着,倒着考慮比較容易,首先把所有的數放到一塊,如果是'<'或者'>',就是去掉最左邊或者最右邊的數,這樣顯然只有一種可能,答案不變。
如果是'?',那麼顯然可以去掉中間的任意一個,所以答案就是\(\times l-2\),那麼對於\(s_n-i\)位置的\(?\),他的貢獻就是\(n-i-1\)倍,總而言之,如果\(s_j\)\(?\),那麼答案就\(\times j-1\)就可以了。
正着考慮呢??首先把通過\(<\)\(>\)加進來的數記作\(X\),而通過\(?\)加進來的數記作\(Y\),顯然的一點就是最後,會充滿整個序列,並且有貢獻的在於\(Y\),因爲\(X\)在加入的時候沒有選擇位置的能力,但是\(Y\)可以插入任何兩個\(X\)的中間,那麼我們要算的,就是每個\(Y\)有多少種插入位置。顯然對於某一串\(Y\),內部的插入順序是無所謂的,如果他們的長度爲\(l\),那麼對於答案的貢獻就是\(l!\),然後我們再來考察單個\(Y\)插入的過程,設現在一共有\(k\)個空白,第\(i\)個空白的長度爲\(L_i\),那麼顯然,如果這個\(Y\)插到了第\(i\)個空白裏,對於答案的貢獻就是\(L_i+1\)倍,然後我們求和,\(\sum_{i=1}^{k} (L_i+1)=\sum_{i=1}^kL_i+k=i-1\),會驚奇的發現無論如何,答案的貢獻非常簡單,\(i-1\)倍。
然後答案爲\(0\)的情況只在第一個字符是\(?\)的情況下出現,進行特殊標記一下,配合上乘法逆元就可以了。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
#include<ctime>
#include<bitset>
#define int long long
using namespace std;
int mod=998244353;
int inv[300009];
int n,m;
string s;
int invv(int a,int n){
	int ans=1;
	while(n){
		if(n&1){
			ans=(ans*a)%mod;
		}
		a=a*a%mod;
		n>>=1;
	}
	return ans;
}
void up(int &res,int x){
	res=(res*x)%mod;
}
int x;
char c;
signed main(){
	inv[1]=1;
	scanf("%lld",&n);
	for(int i=2;i<=n;++i){
		inv[i]=invv(i,mod-2);
	}
	scanf("%lld",&m);
	//cout<<inv[3]*3%mod;
	cin>>s;
	int f=0;
	int ans=1;
	int l=s.length();
	for(int i=0;i<l;++i){
		if(s[i]=='?'){
			if(i==0) f=1;
			else up(ans,i);
		}
	}
	printf("%lld\n",f?0:ans);
	for(int i=1;i<=m;++i){
		scanf("%lld",&x);
		cin>>c;
		x--;
		if(c=='?'&&(s[x]=='<'||s[x]=='>')){
			if(x==0) f=1;
			else
			up(ans,x);
		}
		if(c!='?'&&s[x]=='?'){
			if(x==0) f=0;
			else up(ans,inv[x]);
		}
		s[x]=c;
		printf("%lld\n",f?0:ans);
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章