题解 P9969 [THUPC 2024 初赛] 分治乘法

· · 题解

不会做,但是乱搞过了。

直接分治乘或合并果子面对五十万个 1 要操作九百九十七万次,几乎是题目限制的两倍,但这已经是前两个操作的最优结果,所以考虑用第三个操作进行优化。

有一个很 naive 的想法是把所有长度为二的连续段的第一个元素用操作一构造出来,再用操作三平移构造第二个元素,最后合并果子。在 1 很稠密的时候这个东西确实能优化很多,但是仍然会被五十万个 1 薄纱。。。

五十万个 1 疑似有点极端稠密了。。。于是我们也极端一点,把长度为三的连续段也用前述方式构造出来再合并果子,注意控制好阈值,然后这个东西薄纱五十万个 1 了。。。然后在五十万个 1 里随机加 0 拍了一千组也轻松薄纱。。。然后交上去过了。

实际上这个阈值貌似瞎取也没太大问题。

不会证也不会 hack,给出参考代码供大家薄纱。

#include<bits/stdc++.h>
using namespace std;
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops")
#define ALL(v) v.begin(),v.end()
#define For(i,_) for(int i=0,i##end=_;i<i##end;++i) // [0,_)
#define FOR(i,_,__) for(int i=_,i##end=__;i<i##end;++i) // [_,__)
#define Rep(i,_) for(int i=(_)-1;i>=0;--i) // [0,_)
#define REP(i,_,__) for(int i=(__)-1,i##end=_;i>=i##end;--i) // [_,__)
typedef long long ll;
typedef unsigned long long ull;
#define V vector
#define pb push_back
#define pf push_front
#define qb pop_back
#define qf pop_front
#define eb emplace_back
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
#define fi first
#define se second
const int dir[4][2]={{-1,0},{0,1},{1,0},{0,-1}},inf=0x3f3f3f3f,mod=1e9+7;
const ll infl=0x3f3f3f3f3f3f3f3fll;
template<class T>inline bool ckmin(T &x,const T &y){return x>y?x=y,1:0;}
template<class T>inline bool ckmax(T &x,const T &y){return x<y?x=y,1:0;}
int init=[](){return cin.tie(nullptr)->sync_with_stdio(false),0;}();
#ifdef ONLINE_JUDGE
static char pbuf[1000000],*p1=pbuf,*p2=pbuf,obuf[1000000],*o=obuf;
#define getchar() p1==p2&&(p2=(p1=pbuf)+fread(pbuf,1,1000000,stdin),p1==p2)?EOF:*p1++
#define putchar(x) (o-obuf<1000000)?(*o++=(x)):(fwrite(obuf,o-obuf,1,stdout),o=obuf,*o++=(x))
struct flusher{~flusher(){fwrite(obuf,o-obuf,1,stdout);}}autoflush;
#endif
inline int qr(){
    int in=0;char ch;
    while(!isdigit(ch=getchar()));
    do in=(in<<1)+(in<<3)+(ch^48);while(isdigit(ch=getchar()));
    return in;
}
template<class T>
void qw(T out){
    if(out>9)qw(out/10);
    putchar(out%10|48);
}
inline char gc(){
    char ch;
    while(!isupper(ch=getchar()));
    return ch;
}
int main(){
    int n=qr();
    V<char>a;
    a.reserve(n);
    char ch;
    while(!isdigit(ch=getchar()));
    do a.pb(ch);while(isdigit(ch=getchar()));
    V<V<int>>ans;
    V<int>siz;
    auto cmp=[&](int x,int y){return siz[x]>siz[y];};
    priority_queue<int,V<int>,decltype(cmp)>q(cmp);
    if(count(ALL(a),49)>=300000){
        priority_queue<int,V<int>,decltype(cmp)>_q(cmp);
        For(i,n-2)if((a[i]^48)&&(a[i+1]^48)&&(a[i+2]^48))a[i]=a[i+1]=a[i+2]=48,ans.pb({1,i+1}),siz.pb(1),_q.push(ans.size()-1);
        while(_q.size()>1){
            int x=_q.top();_q.pop();
            int y=_q.top();_q.pop();
            ans.pb({2,x+1,y+1}),siz.pb(siz[x]+siz[y]),_q.push(ans.size()-1);
        }
        int nw=ans.size();
        ans.pb({3,nw,1}),siz.pb(siz[nw-1]);
        ans.pb({3,nw+1,1}),siz.pb(siz[nw]);
        ans.pb({2,nw,nw+1}),siz.pb(siz[nw-1]+siz[nw]);
        ans.pb({2,nw+2,nw+3}),siz.pb(siz[nw+1]+siz[nw+2]);
        q.push(nw+3);
    }
    if(count(ALL(a),49)>=150000){
        priority_queue<int,V<int>,decltype(cmp)>_q(cmp);
        For(i,n-1)if((a[i]^48)&&(a[i+1]^48))a[i]=a[i+1]=48,ans.pb({1,i+1}),siz.pb(1),_q.push(ans.size()-1);
        while(_q.size()>1){
            int x=_q.top();_q.pop();
            int y=_q.top();_q.pop();
            ans.pb({2,x+1,y+1}),siz.pb(siz[x]+siz[y]),_q.push(ans.size()-1);
        }
        int nw=ans.size();
        ans.pb({3,nw,1}),siz.pb(siz[nw-1]);
        ans.pb({2,nw,nw+1}),siz.pb(siz[nw]<<1);
        q.push(nw+1);
    }
    For(i,n)if(a[i]^48)ans.pb({1,i+1}),siz.pb(1),q.push(ans.size()-1);
    while(q.size()>1){
        int x=q.top();q.pop();
        int y=q.top();q.pop();
        ans.pb({2,x+1,y+1}),siz.pb(siz[x]+siz[y]),q.push(ans.size()-1);
    }
    qw(ans.size()),putchar(10);
    for(auto &i:ans){
        for(int j:i)qw(j),putchar(32);
        putchar(10);
    }
    return 0;
}