QOJ.ac
QOJ
ID | Problem | Submitter | Result | Time | Memory | Language | File size | Submit time | Judge time |
---|---|---|---|---|---|---|---|---|---|
#165585 | #6513. Expression 3 | ucup-team870 | RE | 3613ms | 16692kb | C++17 | 6.3kb | 2023-09-05 19:30:12 | 2023-09-05 19:30:12 |
Judging History
answer
#include<bits/stdc++.h>
using namespace std;
#define IOS {cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);}
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define Rep(i,j,k) for(int i=j;i<k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define P pair<int,int>
#define ll long long
#define vi vector<int>
const int N = 2e5+5, mod = 998244353, G = 3;
ll qp(ll x, ll y) {
ll res = 1;
while (y) {
if (y & 1)res = res * x % mod;
x = x * x % mod; y >>= 1;
}return res;
}
const int Gi = qp(G, mod - 2);
ll fac[N], inv[N];
namespace Poly {
typedef vi poly;
int limit = 1, L = 0; int r[N * 4];
void NTT(poly& A, int type) { //下标在[0,limit)范围内,数组开四倍即可
A.resize(limit);
for (int i = 0; i < limit; i++)
if (i < r[i]) swap(A[i], A[r[i]]);
for (int mid = 1; mid < limit; mid <<= 1) {
ll Wn = qp(type == 1 ? G : Gi, (mod - 1) / (mid << 1)); //G是模数的原根,Gi是逆元
for (int j = 0; j < limit; j += (mid << 1)) {
ll w = 1; //ll不一定够
for (int k = 0; k < mid; k++, w = (w * Wn) % mod) {
int x = A[j + k], y = w * A[j + k + mid] % mod; //int不一定够
A[j + k] = (x + y) % mod, A[j + k + mid] = (x - y + mod) % mod;
}
}
}
}
poly operator + (poly a, poly b) {
int n = max(a.size(), b.size());
a.resize(n); b.resize(n);
rep(i, 0, n - 1)a[i] = (a[i] + b[i]) % mod;
return a;
}
poly operator - (poly a, poly b) {
int n = max(a.size(), b.size());
a.resize(n); b.resize(n);
rep(i, 0, n - 1)a[i] = (a[i] - b[i] + mod) % mod;
return a;
}
void poly_mul_init(poly& a, poly& b) {
limit = 1; L = 0;
int N = a.size() - 1, M = b.size() - 1;
while (limit <= N + M) limit <<= 1, L++;
for (int i = 0; i < limit; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
}
poly poly_mul(poly a, poly b) { //原先的a,b不需要维持原状的话,可以加&
int n = a.size() + b.size() - 1;
poly_mul_init(a, b);
NTT(a, 1); NTT(b, 1);
for (int i = 0; i < limit; i++) a[i] = 1ll * a[i] * b[i] % mod; //a[i]为ll不一定够
NTT(a, -1);
ll INV = qp(limit, mod - 2);
rep(i, 0, limit - 1)a[i] = a[i] * INV % mod;
a.resize(n); return a;
}
poly poly_inv(poly& a, int n) {
if (n == 0)return { (int)qp(a[0],mod - 2) };
int n2 = n / 2;
poly b = poly_inv(a, n2);
poly ta(n + 1); rep(i, 0, n)ta[i] = a[i];
/*等价于:
poly ans=poly_mul(ta,b); ans.resize(n+1);
rep(i,0,n)ans[i]=(((i==0)?2:0)-ans[i]+mod)%mod;
ans=poly_mul(b,ans); ans.resize(n+1); return ans;*/
b.resize(n + 1); //ta和b的阶数一定要相同
poly_mul_init(ta, b);
NTT(ta, 1); NTT(b, 1);
rep(i, 0, limit)b[i] = (2 - 1ll * ta[i] * b[i] % mod + mod) * b[i] % mod; //蝴蝶变换这里每一项2-,然而多项式乘法时还是{2,0,0...}
NTT(b, -1);
ll inv = qp(limit, mod - 2);
rep(i, 0, n)b[i] = b[i] * inv % mod;
b.resize(n + 1); ta.clear(); ta.shrink_to_fit();
return b;
}
poly poly_derivate(poly& a) { //求导
int n = (int)a.size() - 1; poly da(n + 1);
rep(i, 1, n)da[i - 1] = 1ll * a[i] * i % mod;
return da;
}
poly poly_integral(poly& a) { //积分
int n = (int)a.size(); poly ia(n + 1);
rep(i, 1, n)ia[i] = 1ll * a[i - 1] * qp(i, mod - 2) % mod;
return ia;
}
poly poly_ln(poly a) {
int n = (int)a.size() - 1;
assert(a[0] == 1);
poly da = poly_derivate(a);
a = poly_inv(a, n);
poly b = poly_mul(a, da); b.resize(n + 1);
vi res = poly_integral(b); res.resize(n + 1); return res;
}
poly poly_exp(poly& a, int n) { //牛顿迭代, nxtg = g*(1-ln(g)+A)
if (n == 0) {
assert(a[0] == 0); return { 1 };
}
int n2 = n / 2;
poly g = poly_exp(a, n2); g.resize(n + 1);//这里求逆要扩展g
poly lng = poly_ln(g);
rep(i, 0, n)lng[i] = ((i == 0) + a[i] - lng[i] + mod) % mod;
poly res = poly_mul(g, lng); res.resize(n + 1);
return res;
}
//多项式ln+exp可以用来优化多项式快速幂:f(x)^m = exp(ln(f(x))*m)
poly poly_pow(poly a, int y) { //a[0]=1. a[0]=0的时候直接移位; 非0的时候整个多项式/a[0],最终结果再*qp(a[0],y)
assert(a[0] == 1);
int n = (int)a.size() - 1;
poly lna = poly_ln(a);
rep(i, 0, n)lna[i] = 1ll * lna[i] * y % mod;
return poly_exp(lna, n);
}
void cdq_fft(poly& f, poly& g, int l, int r) { //f=F(f)*g形式,考虑[l,mid]对[mid+1,r]的贡献,一次poly_mul即可
if (l == r)return;
int mid = l + r >> 1;
cdq_fft(f, g, l, mid);
poly b(r - l + 1); rep(i, 0, r - l)b[i] = g[i];
poly a(mid - l + 1); rep(i, 0, mid - l)a[i] = f[i + l];
poly res = poly_mul(a, b);
rep(i, mid + 1, r)f[i] = (f[i] + res[i - l]) % mod;
cdq_fft(f, g, mid + 1, r);
}
}
using namespace Poly;
char s[N];
signed main() {
const int M = 2e5;
fac[0] = 1; rep(i, 1, M)fac[i] = fac[i - 1] * i % mod;
inv[M] = qp(fac[M], mod - 2); per(i, M, 1)inv[i - 1] = inv[i] * i % mod;
int v=1;
vi lg(M+1),b(M+2),c(M+1);
rep(i,0,mod-2){
if(v<=M)lg[v]=i;
v=1ll*v*G%mod;
}
// cerr<<clock(); return 0;
int n;cin>>n;
vi a(n+1); rep(i,1,n)cin>>a[i];
cin>>s+1;
vi sgn(n+1); sgn[0]=1;
rep(i,1,n-1)sgn[i]=(s[i]=='+'?1:-1),c[i]=i+1-sgn[i],++b[c[i]];
vi res=poly_mul(lg,b);
ll ans=0;
rep(i,1,n){
ll prc=1;
rep(j,1,i-1)prc=prc*(i-c[j])%mod;
prc=(prc+mod)%mod;
// ans=(ans+a[i]*inv[i-1]%mod*prc)%mod;
ll val=qp(G,res[i]);
rep(j,max(1,i-2),i-1){
if(c[j]==i)val=0;
else if(c[j]==i+1)val=(mod-val)%mod;
}
assert(prc==val);
// cout<<val<<'\n';
ans=(ans+a[i]*inv[i-1]%mod*val)%mod;
}
cout<<ans*fac[n-1]%mod<<'\n';
}
/*
4
9 1 4 1
-+-
5
1 2 3 4 5
+-+-
*/
Details
Tip: Click on the bar to expand more detailed information
Test #1:
score: 100
Accepted
time: 3606ms
memory: 16580kb
input:
4 9 1 4 1 -+-
output:
46
result:
ok 1 number(s): "46"
Test #2:
score: 0
Accepted
time: 3613ms
memory: 16692kb
input:
5 1 2 3 4 5 +-+-
output:
998244313
result:
ok 1 number(s): "998244313"
Test #3:
score: -100
Dangerous Syscalls
input:
100000 664815434 205025136 871445392 797947979 379688564 336946672 231295524 401655676 526374414 670533644 156882283 372427821 700299596 166140732 677498490 44858761 185182210 559696133 813911251 842364231 681916958 114039865 222372111 784286397 437994571 152137641 650875922 613727135 209302742 5321...