[examination summary] March 6, 2022

Posted by Gazan on Mon, 07 Mar 2022 12:39:48 +0100

High dimensional walk

Firstly, using Kummer's theorem, it is found that only by dividing \ (t_0 \) into \ (\ {a_0\dots a_m\},\forall i\neq j,a_i\cap a_j=\emptyset,\forall i,a_i\subseteq t_0\cap t_i \) can odd numbers be formed in combinatorial numbers

The simplest idea is to use std::bitset directly to calculate parity for each \ (f(i) \), but the problem can be simplified by dividing stages

Bit by bit transfer is a good choice. Let \ (g {I, X} \) indicate that the first \ (0\sim i \) bit and the value of \ (f(x)\bmod 2 \) have been transferred. If the \ (i+1 \) bit of the transfer enumeration is selected by which \ (a_j \), the \ (g {i+1, J \ times2 ^ {i+1} + X} \) can be updated

At this time, if \ (x\bmod 2^{i+1} \) is grouped, then \ (x+j\times 2^{i+1}\equiv x\mod 2^{i+1} \), that is, the change of parity will only occur in the group

Since the weight transferred does not exceed \ (2^i \), the number of non-zero \ (x \) in each group will not exceed \ (m\times 2^i \), that is, there are no more than \ (m \) elements in each group. According to the weight is \ (0 / 1 \), binary bit compression can be used

In essence \ (0 / 1 \) indicates that different groups are of the order of \ (\ Theta(2^m) \), so it'S stupid to open a variable for each remainder, and then open the bucket \ (ton_S \) indicates the number of groups that are \ (S \) after compression

For the bits not included in \ (t_0 \), the change from \ (S\bmod\ 2_i\to x \bmod\ 2^{i+1} \) is that the quotient is odd and the quotient is even are separated, so the change can be preprocessed

For the bits contained in \ (t_0 \), you need to enumerate the same \ (t_i \) and turn the scheme number into an even XOR, then transfer it

Code Display
const int N=2000010;
int t[N],n,m,dp[2][N],ev[N],od[N];
signed main(){
    freopen("travel.in","r",stdin); freopen("travel.out","w",stdout);
    for(int i=1;i<=N-10;++i){
        ev[i]=(ev[i>>2]<<1)|((i>>1)&1);
        od[i]=(od[i>>2]<<1)|(i&1);
    }
    int T=read(); while(T--){
        n=read(); rep(i,0,n) t[i]=read();
        int cur=0,S=(1<<(n+1)); --S;
        dp[cur][1]=1;
        for(int i=0;i<31;++i){
            if(t[0]>>i&1){
                for(int st=0;st<=S;++st) if(dp[cur][st]){
                    int nxt=st;
                    for(int j=1;j<=n;++j) if(t[j]>>i&1) nxt^=(st<<j);
                    dp[cur^1][ev[nxt]]+=dp[cur][st];
                    dp[cur^1][od[nxt]]+=dp[cur][st];
                    dp[cur][st]=0;
                }
            }else{
                for(int st=0;st<=S;++st) if(dp[cur][st]){
                    dp[cur^1][ev[st]]+=dp[cur][st];
                    dp[cur^1][od[st]]+=dp[cur][st];
                    dp[cur][st]=0;
                }
            }
            cur^=1;
        }
        int ans=0;
        for(int i=1;i<=S;++i) ans+=dp[cur][i]*__builtin_popcount(i),dp[cur][i]=0;
        print(ans);
    }
    return 0;
}

Roller Coaster

If only the legitimacy is judged, the method is to divide each point into two horizontal / vertical points and pull out another origin

After black-and-white staining, the origin is connected to the edge with flow of \ (2 \) to the source point / sink point, and connected to the edge with flow of \ (2 \) to both horizontal and vertical points

Connect the horizontal / vertical points of each point according to the grid diagram to see if the maximum flow is the number of points

If the solution method of "reducing the vertical edge" is considered for the additional weight, the flow from the origin to the transverse / longitudinal point is one with \ (0 \) weight and the other with \ (a_{i,j} \) weight

Since it is the minimum cost maximum flow, you must first select two \ (0 \) weight edges, that is, the method of turning

Code Display
const int N=1e5+10,inf=0x3f3f3f3f;
struct edge{int to,nxt,lim,cst;}e[N<<2];
int head[N],dst[N],pre[N],incf[N];
int tot,id1[200][200],id[200][200],id2[200][200],S,T;
int n,m,cnt=1,ban[200][200],val[200][200];
bool inq[N];
inline bool spfa(){
    for(int i=1;i<=tot;++i) incf[i]=0,dst[i]=inf; dst[S]=0; incf[S]=inf;
    queue<int> q; q.push(S);
    while(q.size()){
        int fr=q.front(); q.pop(); inq[fr]=0;
        for(int i=head[fr];i;i=e[i].nxt) if(e[i].lim){
            int t=e[i].to; if(dst[fr]+e[i].cst<dst[t]){
                dst[t]=dst[fr]+e[i].cst; incf[t]=min(incf[fr],e[i].lim); pre[t]=i;
                if(!inq[t]) inq[t]=1,q.push(t);
            }
        }
    }
    return dst[T]!=inf;   
}
inline void adde(int u,int v,int w,int c){
    e[++cnt]={v,head[u],w,c}; head[u]=cnt;
    return ;
}
inline void add(int u,int v,int w,int c){return adde(u,v,w,c),adde(v,u,0,-c);}
signed main(){
    freopen("roller.in","r",stdin); freopen("roller.out","w",stdout);
    n=read(); m=read();
    int sum=0,block=0;
    S=++tot; T=++tot;
    rep(i,1,n) rep(j,1,m) ban[i][j]=read();
    rep(i,1,n) rep(j,1,m){
        val[i][j]=read();
        sum+=(!ban[i][j])*val[i][j];
        block+=!ban[i][j];
        if(!ban[i][j]){
            id1[i][j]=++tot,id2[i][j]=++tot,id[i][j]=++tot;
            if((i+j)&1){
                add(S,id[i][j],2,0);
                add(id[i][j],id1[i][j],1,0);
                add(id[i][j],id1[i][j],1,val[i][j]);
                add(id[i][j],id2[i][j],1,0);
                add(id[i][j],id2[i][j],1,val[i][j]);
            }else{
                add(id[i][j],T,2,0);
                add(id1[i][j],id[i][j],1,0);
                add(id1[i][j],id[i][j],1,val[i][j]);
                add(id2[i][j],id[i][j],1,0);
                add(id2[i][j],id[i][j],1,val[i][j]);
            }
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j) if(!ban[i][j]&&(i+j)%2){
            if(i+1<=n&&!ban[i+1][j]) add(id1[i][j],id1[i+1][j],1,0);
            if(i-1&&!ban[i-1][j]) add(id1[i][j],id1[i-1][j],1,0);
            if(j+1<=m&&!ban[i][j+1]) add(id2[i][j],id2[i][j+1],1,0);
            if(j-1&&!ban[i][j-1]) add(id2[i][j],id2[i][j-1],1,0);
        }   
    }
    int flow=0;
    while(spfa()){
        int x=T;
        while(x!=S){
            e[pre[x]].lim-=incf[T];
            e[pre[x]^1].lim+=incf[T];
            x=e[pre[x]^1].to;
        }
        flow+=incf[T]; sum-=incf[T]*dst[T];
    }
    if(flow==block) print(sum);
    else print(-1);
    return 0;
}

road toll

Convert the line segment to the left end point (that is, let the right end point of the limit be \ (- k \), and remember that \ (s_i \) represents the number of left end points on the first \ (I \)

Then the segment length is \ (K \ leftrightarrow \) \ (\ forall, l, R, s_, r-s_{l} \ Le \ lceil \ frac {R-L} K \ rceil \)

For the limit of \ (m \), that is \ (s_{x-1}\ge s_y-c \)\ The position of (n \) sticks can be expressed as \ (s {B I} \ ge s {A-1} + 1 \), and finally there is \ (s {I} \ ge s {I + 1} - 1 \) according to the actual meaning

First investigate \ (s_{b}\ge s_a+1 \), let \ (U(l,r) \) represent the number of line segments in the interval \ ([l,r] \), and use the \ (\ rm Hall \) theorem to find that the limit of \ ((a,b) \) needs to be expressed as \ (s_r-s_{l-1}\ge U(l,r) \)

\When (n \) is large, this method of edge connection cannot be accepted. Try to keep only the left end point \ (- 1 \) and the right end point of the "limit interval" as the key point and the edge involved in the key point (i.e. export subgraph) for differential constraint

For a positive ring that is not all key points on the original graph, find a non key point, and its connecting edge on the ring cannot be the edge in the \ (m \) limit. If there are continuous \ (\ ge U(l,r) \) or \ (\ le -\lceil\frac {len}k\rceil \) edges, merging will not reduce the weight of the ring

Then keeping \ (U(l,r) \) unchanged and reducing the interval corresponding to this point will not reduce the weight on the ring, so we can only make differential constraints on the derived subgraph

In the process of differential constraint, observe the composition of edges, and it is easy to use \ (\ Theta(n+m) \) to process \ (s_i\le s_{i+1},s_{x-1}\ge s_y-c \)

For \ (s_r-s_{l-1}\ge U(l,r) \), this is a classical scanline problem, which can be expressed as \ (s_r \ Ge \ Max \ limits_{l < R} \ {s_{L-1} + U (L, R) \} \) in my chkmax differential constraint

The fourth \ (s_r-s {l} \ Le \ lceil \ frac {R-L} K \ rceil \ rightarrow s_l \ Ge s_r - \ lceil \ frac rk \ rceil + \ lceil \ frac LK \ rceil - (R \ bmod \ k > L \ bmod \ K) \) can sort \ (i\in[1,n] \) according to the remainder of module \ (K \), and then use \ (\ text {Fenwick Tree} \) to maintain the maximum suffix value

Note that the updates are in order. During the positive sequence scanning, the congruences are inserted into the query first, while in the reverse sequence, they should be queried first and then inserted to avoid missing transfer or wrong transfer

If there is no room for constant optimization after replacing the line segment tree with zkw line segment tree, I don't know how \ (\ text{std} \) is done, so I can only clamp the length of the positive ring to \ (3000 \)

Code Display
const int N=4010,inf=0x3f3f3f3f;
int n,m,k,x[N],y[N],c[N],a[N],b[N];
int num,ar[N];
vector<int> inter[N];
int now[N],nxt[N];
struct Fenwick{
    int c[N];
    inline void clear(){memset(c,-0x3f,sizeof(c));}
    inline void insert(int x,int v){
        for(;x;x-=x&(-x)) ckmax(c[x],v);
        return ;
    }
    inline int query(int x){
        int Mx=0;
        for(;x<=num;x+=x&(-x)) ckmax(Mx,c[x]);
        return Mx;
    }
}T;
struct Seg{
#define ls p<<1
#define rs p<<1|1
    int Mx[N<<2],tag[N<<2],bit;
    inline void push_up(int p){Mx[p]=max(Mx[ls],Mx[rs])+tag[p];}
    inline void build(int n){
        bit=1; while(bit<=n+1) bit<<=1;
        for(int i=bit+1;i<=bit+n;++i) Mx[i]=now[i-bit],tag[i]=0;
        for(int i=bit-1;i>=1;--i) Mx[i]=max(Mx[i<<1],Mx[i<<1|1]),tag[i]=0;
        return ;
    }
    inline void upd(int st,int ed){
        st+=bit-1; ed+=bit+1;
        while(st!=ed-1){
            if(!(st&1)) Mx[st^1]++,tag[st^1]++;
            if(ed&1) Mx[ed^1]++,tag[ed^1]++;
            push_up(st>>=1); push_up(ed>>=1);
        } 
        while(st>>1) push_up(st>>=1);
        return ;
    }
    inline int query(int st,int ed){
        st+=bit-1; ed+=bit+1;
        int lef=0,rig=0;
        while(st!=ed-1){
            if(!(st&1)) ckmax(lef,Mx[st^1]);
            if(ed&1) ckmax(rig,Mx[ed^1]);
            lef+=tag[st>>=1]; rig+=tag[ed>>=1];
        }
        int Mx=max(lef,rig);
        while(st>>1) Mx+=tag[st>>=1];
        return Mx;
    }
#undef ls
#undef rs
}seg;
int quo[N],rem[N],id[N];
signed main(){
    freopen("stick.in","r",stdin); freopen("stick.out","w",stdout);
    n=read(); m=read(); k=read(); 
    rep(i,1,n){
        a[i]=read(),b[i]=read()-k;
        ar[++num]=a[i]-1; ar[++num]=b[i];
    }
    rep(i,1,m){
        x[i]=read(),y[i]=read()-k,c[i]=read();
        ar[++num]=x[i]-1; ar[++num]=y[i];
    }
    sort(ar+1,ar+num+1); num=unique(ar+1,ar+num+1)-ar-1;
    rep(i,1,num){
        quo[i]=ar[i]/k,rem[i]=(ar[i]%k+k)%k,id[i]=i;
        while(k*quo[i]>ar[i]) quo[i]--;
    }
    sort(id+1,id+num+1,[&](const int &x,const int &y){return rem[x]<rem[y];});
    rep(i,1,n){
        a[i]=lower_bound(ar+1,ar+num+1,a[i]-1)-ar;
        b[i]=lower_bound(ar+1,ar+num+1,b[i])-ar;
        inter[b[i]].push_back(a[i]);
    }
    rep(i,1,m){
        x[i]=lower_bound(ar+1,ar+num+1,x[i]-1)-ar;
        y[i]=lower_bound(ar+1,ar+num+1,y[i])-ar;
    }
    //four kinds of edges
    // first -> s[x[i]-1]>=s[y[i]]+c;
    // second-> s[i]<=s[i+1]
    // third -> s[i]>=s[j]-(i-j+k-1)/k
    // fourth-> scaning line
    memset(now,-0x3f,sizeof(now)); now[0]=0;
    memset(nxt,-0x3f,sizeof(nxt));
    for(int turn=1;turn<=num;++turn){
        nxt[0]=now[0];
        for(int i=1;i<=num;++i) nxt[i]=max(nxt[i-1],now[i]);
        //second type
        for(int i=1;i<=m;++i) ckmax(nxt[x[i]],now[y[i]]-c[i]);
        //first type
        seg.build(num);
        for(int i=1;i<=num;++i){
            for(auto t:inter[i]) seg.upd(1,t);
            if(i-1) ckmax(nxt[i],seg.query(1,i-1));
        }
        //scaning line
        T.clear();
        for(int i=1;i<=num;++i){
            int rig=i;
            while(rig<num&&rem[id[rig+1]]==rem[id[i]]) ++rig;
            for(int j=i;j<=rig;++j) T.insert(id[j],now[id[j]]-quo[id[j]]);   
            for(int j=i;j<=rig;++j) ckmax(nxt[id[j]],T.query(id[j]+1)+quo[id[j]]);
            i=rig;
        }
        T.clear();
        for(int i=num;i>=1;--i){
            int rig=i;
            while(rig>1&&rem[id[rig-1]]==rem[id[i]]) --rig;
            for(int j=i;j>=rig;--j) ckmax(nxt[id[j]],T.query(id[j]+1)+quo[id[j]]-1);
            for(int j=i;j>=rig;--j) T.insert(id[j],now[id[j]]-quo[id[j]]);
            i=rig;
        }
        //third type
        bool updd=0;
        for(int i=1;i<=num;++i) if(now[i]!=nxt[i]){updd=1; break;}
        if(!updd) break;
        if(turn==num) puts("No"),exit(0);
        for(int i=1;i<=num;++i) now[i]=nxt[i],nxt[i]=-inf;
    }
    puts("Yes");
    return 0;
}