20220504
私货:今天打 GSL 决赛,虽然我也很想让 Creator 赢,但 Rogue 的决赛准备真的太好了,奶一口 Rogue 4:1 夺冠
- tot 100 (175)
- rk 8/22
路人女主
0pt, max = 100pts
暴力没写完,赛后写完发现 T 了/kk 算复杂度的时候注意多测
\(s_{i}s_{i+1},t_{i}t_{i+1}\) 中一定有相同字符,因此 \(s,t\) 的 LCS 至少为 \(n\)。可以发现合法的串只有两类:
- \(s=ababa\cdots,t_{2i+1}=c,t_{2i}=a\text{ or }b\)
- \(s_{2i}=t_{2i}=a,\exists k\),\(s\) 的前 \(k\) 个奇数位置为 \(b\),后面为 \(c\),\(t\) 相反
可以归纳证明,非常繁琐,看官方题解吧。可能更靠谱的做法是打表
注意去重:\(aba,cac\) 同时属于第一类和第二类,被算了两遍;\(aba,cbc\) 在第一类中被 \(s,t\) 和 \(t,s\) 各算了一遍,总共三遍
code
const int N = 2e6+5;
int n,m;
LL ans,pw[N];
char s[N],t[N];
bool eq(char x,char y) { return x=='?' || x==y; }
void cal1(char *s,char *t,char a,char b,char c) {
int cnt = 0;
for(int i = 1; i <= m; i += 2) if( !eq(s[i],a) || !eq(t[i],c) ) return;
for(int i = 2; i <= m; i += 2) {
if( !eq(s[i],b) || t[i] == c ) return;
cnt += t[i]=='?';
}
ans += pw[cnt];
}
void cal2(char a,char b,char c) {
int cnt = 0;
for(int i = 2; i <= m; i += 2) if( !eq(s[i],a) || !eq(t[i],a) ) return;
for(int i = 1; i <= m; i += 2) cnt += eq(s[i],b) + eq(t[i],c);
ans -= cnt==2*(n+1);
for(int i = 1; i < m; i += 2)
cnt += eq(s[i],c)-eq(s[i],b) + eq(t[i],b)-eq(t[i],c),
ans += cnt==2*(n+1);
}
void MAIN() {
io>>n>>s+1>>t+1, m = 2*n+1;
auto slv=[](char a,char b,char c)
{ cal1(s,t,a,b,c), cal1(t,s,a,b,c), cal2(a,b,c); };
slv('A','B','C'), slv('A','C','B'), slv('B','A','C'),
slv('B','C','A'), slv('C','A','B'), slv('C','B','A');
io<<Mod(ans%mod)<<endl;
} signed main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout);
pw[0] = 1; Rep(i,1,N) pw[i] = pw[i-1] * 2 %mod;
int t; io>>t; while( t-- ) ans = 0, MAIN();
return 0;
}
铃原露露
100pts
做了一整场。思考时断时续,坚信做法没问题因此一直在刚,最后 15min 才写完,运气很好没怎么调。其实思路很顺,代码又全是板子,最慢应该 2.5h 过掉的
考场代码
const int N = 2e5+5;
int n,m,a[N],fa[N],siz[N],le[N],ri[N],pre[N],suf[N];
LL ans[N];
Vi e[N],c[N];
vector<Pii> q[N],b[N];
set<int> s[N];
#define ls (u<<1)
#define rs (u<<1|1)
#define mid (l+r>>1)
struct Seg {
int t[N*4];
Seg() { memset(t,0x3f,sizeof t); }
void mdf(int ql,int qr,int x,int u=1,int l=1,int r=n) {
if( qr < l || r < ql ) return;
if( ql <= l && r <= qr ) return ckmin(t[u],x), void();
mdf(ql,qr,x,ls,l,mid), mdf(ql,qr,x,rs,mid+1,r);
}
void dfs(int x,int *a,int u=1,int l=1,int r=n) {
ckmin(x,t[u]);
if( l == r ) return a[l] = x, void();
dfs(x,a,ls,l,mid), dfs(x,a,rs,mid+1,r);
}
} t1,t2;
void dfs(int u) {
int son = 0; siz[u] = 1;
for(int v : e[u]) { dfs(v), siz[u] += siz[v]; if( siz[v] > siz[son] ) son = v; }
if( son ) {
swap(s[u],s[son]);
for(int v : e[u]) if( v != son ) {
for(int x : s[v]) {
auto add=[&](int x,int y) {
if( a[u] < x ) t1.mdf(a[u]+1,x,y);
else if( y < a[u] ) t2.mdf(y,a[u]-1,-x);
};
auto it = s[u].lwb(x);
if( it != s[u].end() ) add(x,*it);
if( it != s[u].begin() ) add(*--it,x);
}
s[u].insert(all(s[v]));
}
}
s[u].emplace(a[u]);
}
struct {
LL t1[N],t2[N];
void add(int p,int x) { for(int i=p;i<=n;i+=i&-i) t1[i] += x, t2[i] += p*x; }
void add(int l,int r,int x) { add(l,x), add(r+1,-x); }
LL sum(int p) {
LL res = 0;
for(int i=p;i;i-=i&-i) res += (p+1)*t1[i] - t2[i];
return res;
}
LL sum(int l,int r) { return sum(r) - sum(l-1); }
} bit;
#define ls (u<<1)
#define rs (u<<1|1)
#define mid (l+r>>1)
struct {
struct { int sum,cnt; LL res; } t[N*4];
void down(int u,int x) { t[u].res += (LL)x * t[u].sum, t[u].cnt += x; }
void down(int u) { down(ls,t[u].cnt), down(rs,t[u].cnt), t[u].cnt = 0; }
void ins(int p,int u=1,int l=1,int r=n) {
++t[u].sum;
if( l == r ) return;
down(u), p<=mid ? ins(p,ls,l,mid) : ins(p,rs,mid+1,r);
}
void add(int qr,int u=1,int l=1,int r=n) {
if( qr < l ) return;
if( r <= qr ) return down(u,1);
down(u), add(qr,ls,l,mid), add(qr,rs,mid+1,r),
t[u].res = t[ls].res + t[rs].res;
}
LL sum(int ql,int qr,int u=1,int l=1,int r=n) {
if( qr < l || r < ql ) return 0;
if( ql <= l && r <= qr ) return t[u].res;
return down(u), sum(ql,qr,ls,l,mid) + sum(ql,qr,rs,mid+1,r);
}
} seg;
signed main() { freopen("b.in","r",stdin); freopen("b.out","w",stdout);
io>>n>>m; For(i,1,n) io>>a[i]; For(i,2,n) io>>fa[i], e[fa[i]].pb(i);
For(i,1,m) io>>le[i]>>ri[i], q[le[i]-1].pb(i,-1), q[ri[i]].pb(i,1);
dfs(1), t1.dfs(n+1,suf), t2.dfs(0,pre); For(i,1,n) pre[i] = -pre[i];
For(i,1,n) {
if( suf[i] <= n ) b[i].pb(suf[i],n), c[suf[i]].pb(i);
if( 1 <= pre[i] ) b[i].pb(1,pre[i]);
}
For(i,1,n) {
for(auto j : b[i]) bit.add(j.fi,j.se,1);
for(auto j : q[i]) ans[j.fi] += j.se * bit.sum(le[j.fi],ri[j.fi]);
}
For(i,1,n) {
for(int j : c[i]) seg.ins(j);
seg.add(pre[i]);
for(auto j : q[i]) ans[j.fi] -= j.se * seg.sum(le[j.fi],ri[j.fi]);
}
auto cal=[](LL n) { return n * (n-1) / 2 + n; };
For(i,1,m) io<<cal(ri[i]-le[i]+1)-ans[i]<<endl;
return 0;
}
赫露艾斯塔
0pt, max = 50pts
6s,\(O(n^{3})\) 完全能过 \(10^3\)。赛时应该写这题暴力的,不过马后炮并没有意义
考虑分类讨论 \(-\frac{a}{b},b\) 的正负,\(-\frac{a}{b}<0,b>0\) 的情况是平凡的。若点 \(p\) 合法,那么被 \(p\) 支配的点也合法,只需要预处理每个点能支配多少点。
解决其他情况的关键在于发现合法与非法、支配与非支配是完全等价的,即求得非法的非支配对数(及非法的点数)后也能算出合法支配对数。不同情况算不同的东西即可
问题被转化为了半平面数点,随机数据下有非常简洁的做法。
把平面分成 \(\sqrt{n}\times\sqrt{n}\) 块,那么期望每块中有 \(O(1)\) 个点。一条直线只会穿过 \(O(\sqrt{n})\) 个块,对这些块内的点暴力,整块的点可以对每列做前缀和求出。时间复杂度 \(O(n\sqrt{n})\)
实现上可能需要处理直线与块顶点相交的情况,不过块大小是自己定的应该不会出现,所以直接不管(
我的写法比较粗暴,卡常时间几乎和写代码时间持平,体验极差
code
const int N = 2e5+5, X = 1e4, B = 128, BN = N/B+5;
int n,m,bn;
short *in,le[BN],ri[BN];
LL a,b,c;
double k1,k2;
Pii p[N];
Vi id[BN][BN];
#define x(i) p[i].fi
#define y(i) p[i].se
#define bx(i) in[x(i)]
#define by(i) in[y(i)]
struct {
int t[int(2e4+2)];
void clr() { memset(t,0,sizeof t); }
void add(int i) { for(i+=X+1;i<=2e4+1;i+=i&-i)++t[i]; }
int sum(int i) { int res=0; for(i+=X+1;i;i-=i&-i)res+=t[i]; return res; }
int sum(int l,int r) { return sum(r) - sum(l-1); }
} bit;
namespace sub {
LL pre[N],suf[N];
void init() {
bit.clr(); for(int l = 1, r; l <= n; l = r+1) {
for(r = l; r < n && x(r+1) == x(l); ++r);
For(i,l,r) pre[i] = pre[i-1] + bit.sum(-X,y(i)-1);
For(i,l,r) bit.add(y(i));
}
bit.clr(); for(int r = n, l; r; r = l-1) {
for(l = r; l > 1 && x(l-1) == x(r); --l);
rFor(i,r,l) suf[i] = suf[i+1] + bit.sum(y(i)+1,X);
rFor(i,r,l) bit.add(y(i));
}
}
void slv() {
if( a > 0 ) {
int l = 1, r = n+1, mid;
while( l < r ) mid = l+r>>1, a*x(mid)+c>0 ? r=mid : l=mid+1;
io<<suf[l]<<endl;
} else {
int l = 0, r = n, mid;
while( l < r ) mid = l+r+1>>1, a*x(mid)+c>0 ? l=mid : r=mid-1;
io<<pre[l]<<endl;
}
}
}
struct Block {
int w[N],s[BN][BN];
void bld() {
For(i,1,n) s[bx(i)][by(i)] += w[i];
For(i,1,bn) rFor(j,bn,1) s[i][j] += s[i][j+1];
}
int cal(LL x) {
LL y = k1 * x + k2;
return y<-X ? 0 : y<=X ? in[y] : bn+1;
}
} cnt;
struct : Block {
void init() {
bit.clr(); for(int r = n, l; r; r = l-1) {
for(l = r; l > 1 && x(l-1) == x(r); --l);
rFor(i,r,l) w[i] = bit.sum(y(i)+1,X);
rFor(i,r,l) bit.add(y(i));
}
bld();
}
void slv() {
LL res = 0;
For(i,1,bn) {
int l = cal(le[i]), r = cal(ri[i]); if( l > r ) swap(l,r);
res += s[i][r+1];
For(j,l,r) for(int k : id[i][j])
if( a*x(k)+b*y(k)+c > 0 ) res += w[k];
}
io<<res<<endl;
}
} cs1;
struct : Block {
LL tot;
void init() {
bit.clr(); for(int l = 1, r; l <= n; l = r+1) {
for(r = l; r < n && x(r+1) == x(l); ++r);
For(i,l,r) w[i] = bit.sum(-X,y(i)-1);
For(i,l,r) bit.add(y(i));
} tot = accumulate(w+1,w+n+1,0ll);
bld();
}
void slv() {
LL res = tot;
For(i,1,bn) {
int l = cal(le[i]), r = cal(ri[i]); if( l > r ) swap(l,r);
res -= s[i][r+1];
For(j,l,r) for(int k : id[i][j])
if( a*x(k)+b*y(k)+c <= 0 ) res -= w[k];
}
io<<res<<endl;
}
} cs2;
struct : Block {
void init() {
bit.clr(); for(int l = 1, r; l <= n; l = r+1) {
for(r = l; r < n && x(r+1) == x(l); ++r);
rFor(i,r,l) w[i] = bit.sum(y(i),X), bit.add(y(i));
}
bld();
}
void slv() {
LL n = 0, res = 0;
For(i,1,bn) {
int l = cal(le[i]), r = cal(ri[i]); if( l > r ) swap(l,r);
n += cnt.s[i][r+1], res += s[i][r+1];
For(j,l,r) for(int k : id[i][j])
if( a*x(k)+b*y(k)+c > 0 ) ++n, res += w[k];
}
io<<n*(n-1ll)/2-res<<endl;
}
} cs3;
struct : Block {
LL tot;
void init() {
bit.clr(); for(int r = n, l; r; r = l-1) {
for(l = r; l > 1 && x(l-1) == x(r); --l);
For(i,l,r) w[i] = bit.sum(-X,y(i)), bit.add(y(i));
} tot = accumulate(w+1,w+n+1,0ll);
bld();
}
void slv() {
LL n = ::n, res = tot;
For(i,1,bn) {
int l = cal(le[i]), r = cal(ri[i]); if( l > r ) swap(l,r);
n -= cnt.s[i][r+1], res -= s[i][r+1];
For(j,l,r) for(int k : id[i][j])
if( a*x(k)+b*y(k)+c <= 0 ) --n, res -= w[k];
}
io<<n*(n-1ll)/2-res<<endl;
}
} cs4;
signed main() { freopen("c.in","r",stdin); freopen("c.out","w",stdout);
in = new short[20002]() + 10001;
for(int i = -X; i <= X; i += B) in[i] = ++bn, le[bn] = i;
For(i,1,bn) ri[i] = le[i]+B-1; ri[bn] = X;
For(i,-X,X) if( !in[i] ) in[i] = in[i-1];
io>>n>>m; For(i,1,n) io>>x(i)>>y(i); sort(p+1,p+n+1);
For(i,1,n) id[bx(i)][by(i)].pb(i), cnt.w[i] = 1;
sub::init(), cnt.bld(), cs1.init(), cs2.init(), cs3.init(), cs4.init();
while( m-- ) {
io>>a>>b>>c, k1 = (double)-a/b, k2 = (double)-c/b;
if( !b ) sub::slv();
else if( k1 < 0 ) b>0 ? cs1.slv() : cs2.slv();
else b>0 ? cs3.slv() : cs4.slv();
}
return 0;
}