solution-contest2.26(div2)B
How to solve problem B without your brain
首先有一些很显然的性质,就是如果一个属性不同的球相撞,我们可以视为没发生这次碰撞。否则我们可以看成两个小球的属性发生了改变,但是方向依然不变,穿过去了。所以电荷的正负仅仅代表方向。
套路地,考虑没有 ? 怎么算一个给定序列的答案。我们考虑对于每一个 + 算他是否产生了贡献。发现需要维护当前所有还在往右走的小球的属性。手玩一下,不难把整个过程抽象成下面的过程:
- 初始有一个空的队列。
- 如果是一个 - 号的话,往队尾加入一个 A。
- 如果是一个 + 号的话,如果队头是 A,那么答案 +1,否则没变化。接着,我们弹出队头,并往队尾加入一个 B。
我们会记给定序列的答案了。
首先,这个删除操作看起来非常蠢,所以我们不妨看作原来有一长串仅包含 A,B,? 的序列,然后有一个指针在上面向后移动。
赛时蠢笨了(摆烂了),如果你直接暴力考虑每一个 ? 或者 B 是否会产生贡献,暴力拆贡献直接算那就是
正确的做法应当是考虑每一个 ? 或者 A 是否被贡献。显然的,贡献条件是最终序列的 B 的个数要大于当前位置的下标。预处理组合数后缀和即可做到
总结:我是傻逼。自我感觉我这样子转换后就变得清晰多了。
// Problem: B. 弹性碰撞(physics)
// URL: http://www.gdfzoj.com:23380/contest/929/problem/8760
// Writer: WRuperD
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
const long long inf = 1e18;
const int mininf = 1e9 + 7;
#define int long long
#define pb emplace_back
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void write(int x){if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');}
#define put() putchar(' ')
#define endl puts("")
const int MAX = 2e6 + 10;
const int mod = 998244353;
int quickPower(int a, int b, int p){
int base = a, ans = 1;
while(b){
if(b & 1) ans *= base, ans %= mod;
base *= base, base %= mod;
b >>= 1;
}
return ans;
}
string s;
int fk[MAX], fk2[MAX];
int c2(int n, int m){
if(n == m) return 1;
if(n <= 0) return 0;
if(m > n) return 0;
return fk[n] * fk2[m] % mod * fk2[n - m] % mod;
}
int fk3[MAX];
int fk4[MAX], fk5[MAX];
void solve(){
cin>>s;
int n = s.length();
s = " " + s;
fk[0] = 1;
for(int i = 1; i < MAX; i++) fk[i] = fk[i -1] * i % mod;
fk2[MAX - 1] = quickPower(fk[MAX - 1], mod - 2, mod);
for(int i = MAX - 2; i >= 0; i--){
fk2[i] = fk2[i + 1] * (i + 1) % mod;
}
int tot2 = 0;
for(int i = 1; i <= n; i++){
if(s[i] == '?') tot2++;
}
// write(tot2), endl;
fk3[0] = fk3[1] = 1;
for(int i = 1; i < MAX; i++) fk3[i] = fk3[i - 1] * 2 % mod;
for(int i = tot2; i >= 0; i--){
fk4[i] = fk4[i + 1] + c2(tot2, i);
fk4[i] %= mod;
fk5[i] = fk5[i + 1] + c2(tot2 - 1, i);
fk5[i] %= mod;
}
int pre = 0, ans = 0;
for(int i = 1; i <= n; i++){
if(s[i] == '+') pre++;
}
// write(tot2), endl;
// write(fk5[0]), endl;
// write(fk4[0]), endl;
for(int i = 1; i <= n; i++){
if(s[i] == '-' or s[i] == '?'){
// write(i - pre), put(), write(tot2 - (s[i] == '?')), endl;-
if(i - pre > tot2 - (s[i] == '?')) continue;
// write(i), endl;
if(s[i] == '-'){
if(i <= pre) ans += fk4[0 + s[i] == '?'];
else ans += fk4[i - pre + (s[i] == '?')];
}else{
if(i <= pre) ans += fk5[0];
else ans += fk5[i - pre];
}
// write(ans), endl;
ans %= mod;
}
}
write(ans), endl;
// int ans = 0;
// int pos = 1;
// int pre = 0;
// for(int i = 1; i <= n; i++){
// if(s[i] == '+' or s[i] == '?'){
// for(int j = pos; j < i; j++){+-
// if(j - pos > pre) break;
// if(s[j] == '-'){
// ans += c2(pre, j - pos) * fk3[tot2 - pre - (s[i] == '?')] % mod;
// ans %= mod;
// }else if(s[j] == '?'){
// ans += c2(pre - 1, j - pos) * fk3[tot2 - pre - (s[i] == '?')] % mod;
// ans %= mod;
// }
// }
// if(s[i] == '+'){
// pos++;
// }else{
// pre++;
// }
// }
// }
// write(ans), endl;
}
signed main(){
int t = 1;
while(t--) solve();
return 0;
}