Official

G - Segment Sum Constraints Editorial by en_translator


First, replace \(S_i\) in each condition with \(S_i-(R_i-L_i+1)\) in order to mandate that \(A\) is an non-negative integer sequence. An non-negative integer sequence \(A\) satisfying the modified condition corresponds one-to-one to a positive integer sequence satisfying the original condition, so the answer does not change.

Our solution is two-fold.

Step 1: Determine if there are no contradicting conditions, and find the necessary and sufficient conditions.

Define the cumulative sums \(B\) of \(A\), defined as \(B_0=0, B_i=B_{i-1}+A_i\) \((1\leq i\leq N)\).

The given conditions can be written as \(B_{R_i}-B_{L_i-1}=S_i\).
We will aim at describing these conditions in the form \(B_i=B_{k_i}+D_i\), where \(k_i\) is the smallest index that can be written in this form.
Initially, \(k_i=i, D_i=0\) for all \(i\). For \(i=1,2,\ldots,M\) in order, we perform the following operation depending on the condition:

  • If \(k_{L_i-1}=k_{R_i}\)

By the previous conditions, \(B_{L_i-1}=B_{k_{L_i-1}}+D_{L_i-1}\) and \(B_{R_i}=B_{k_{R_i}}+D_{R_i}\), so in particular \(B_{R_i}=B_{L_i-1}+(D_{R_i}-D_{L_i-1})\).
Thus, if \(S_i\neq D_{R_i}-D_{L_i-1}\), there is no \(A\) satisfying the condition, and the answer is \(0\). (In implementation, you may immediately terminate the program here.) Otherwise, this condition is automatically guaranteed by the conditions so far, so we do not have to do anything; advance to next \(i\).

  • If \(k_{L_i-1}< k_{R_i}\)

The current condition can be written as \(B_{k_{R_i}}+D_{R_i}=B_{L_i-1}=(B_{k_{L_i-1}}+D_{L_i-1})+S_i\), which is equivalent to \(B_{k_{R_i}}=B_{k_{L_i-1}}+(D_{L_i-1}+S_i-D_{R_i})\). Thus, any \(B_j\) that can be written in the form \(B_{k_{R_i}}+\) (constant) can be written in the form \(B_{k_{L_i-1}}+\) (constant), so for all \(j\) with \(k_j=k_{R_i}\), set \(k_j \leftarrow k_{L_i-1}\) and \(D_j \leftarrow D_j+(D_{L_i-1}+S_i-D_{R_i})\) (where \(\leftarrow\) denotes an assignment).

  • If \(k_{L_i-1}> k_{R_i}\)

By the same reason as the \(k_{L_i-1}< k_{R_i}\) case, noticing \(k_{L_i-1}> k_{R_i}\), for all \(j\) with \(k_j=k_{L_i-1}\), set \(k_j \leftarrow k_{R_i}\) and \(D_j \leftarrow D_j+(D_{R_i}-D_{L_i-1}-S_i)\).

After performing the operation for all \(i\), enumerate the conditions for \(j=0,1,\ldots,N-1\) as follows:

  • If there exists no \(j'>j\) such that \(k_{j'}=k_j\), do nothing. If it does, for the smallest such \(j'\), recognize \(A_{j+1}+A_{j+2}+\cdots+A_{j'}=B_{j'}-B_j=D_{j'}-D_j\) as a condition. Here, if \(D_{j'}-D_j\) is less than \(0\), no \(A\) satisfies the condition, so print \(0\).

The set of conditions obtained forms a necessary and sufficient condition of those given as input. The necessity immediately follows by definition of \(k_j\) and \(D_j\). Also, for each condition given as input, \(k_{L_i-1}=k_{R_i}\) is eventually satisfied at the end of the procedures, so one can obtain any original equation by combining the enumerated conditions, that is, the condition is automatically satisfied when the enumerated ones are satisfied.

Also, by definition, there exists a condition in the input whose left hand side is a subarray sum containing the left hand side of one of the conditions, \(A_{j+1}+A_{j+2}+\cdots+A_{j'}\), so the right hand sides of the new conditions are all \(10^9\) or less.

As a conclusion of this step, if there exist contradicting conditions, then they are detected during the operations above; otherwise, a non-negative integer sequence \(A=(A_1,\ldots, A_N)\) satisfies the condition in the input if and only if the conditions,

  • \(A_{L'_i}+\cdots+A_{R'_i}=S'_i\),

enumerated above are satisfied. Because of how they were constructed, \(L'_i\) are guaranteed to be pairwise distinct, so there are at most \(N\) equations. Let \(M'\) be the number of equations.

If some \(A_j\) \((1\leq j\leq N)\) does not appear in any of the \(M'\) equations above, the answer is \(0\) or Infinity. Note that this is equivalent to whether there is \(A_j\) not appearing in any of the \(M\) equations in the original input. We will handle this case later, and for now assume that all \(A_j\) appears at least once. Here, as mentioned already, the right hand sides are all not greater than \(10^9\), so it suffices to consider the case where all \(A_j\) is not greater than \(10^9\).

Step 2. Perform binary digit DP (Dynamic Programming) to find the answer.

Let \(dp[i][(C_1,C_2,\ldots,C_{M'})]\) be the number of combinations of the \(i\) least significant digits of \(A_1,\ldots,A_N\) in binary, such that:

  • \(A_{L'_j}+\cdots+A_{R'_j}\equiv S'_j \pmod{2^i}\) for all \(j=1,2,\ldots,M'\), and
  • \(\{ (A_{L'_j} \% 2^i)+\cdots +(A_{R'_j} \% 2^i)-(S'_j\%2^i)\}/2^i=C_j\) for all \(j=1,2,\ldots,M'\).

Here, \(X\%Y\) denotes the (minimum non-negative) remainder when \(X\) is divided by \(Y\). In particular, \(A_j\%2^i\) is the \(i\) least significant digits of \(A_j\). When the former condition is satisfied, \(C_j\) is always an integer between \(0\) and \((R_j-L_j)\), inclusive.

As mentioned above, we know that the both hand sides of the equalities are at most \(10^9\), so we may assume that the \(31\)-th least significant digit (\(2^{30}\)s place) and higher are all \(0\), and the answer is \(dp[30][(0,0,\ldots,0)]\%998244353\). The initial value is \(dp[0][(0,0,\ldots,0)]=1\), and \(dp[0][C]=0\) for all \(C\neq (0,0,\ldots,0)\).

The transitions from \(dp[i-1][C]\) are generated from all combinations of the \(i\)-th digit of \(A_i\), which we denote by \(X^i=(X^i_1,\ldots,X^i_N)\) \((X^i_j\in\{0,1\})\), that satisfy the condition at the \(i\)-th place.
In other words, if \(d(Z, i)\) denotes the \(i\)-th digit of \(Z\), among the \(2^N\) possible combinations of \(X^i\), for each satisfying

  • \(C_j+X^i_{L'_j}+X^i_{L'_j+1}+\cdots+X^i_{R'_j}\equiv d(S'_j,i) \pmod{2}\),

perform an update \(dp[i][C']\leftarrow dp[i][C']+dp[i][C]\), where

  • \(C'_j=\frac{1}{2}\{C_j+X^i_{L'_j}+X^i_{L'_j+1}+\cdots+X^i_{R'_j}-d(S'_j,i) \}\).

We have figured out how we can find the answer.
Let us analyze the computational complexity. The important point is how many combinations \(C\), which represent carries, there are. There are \((R'_1-L'_1+1)\times (R'_2-L'_2+1)\times \cdots (R_{M'}-L_{M'}+1)\) possible values. When \((L'_j,R'_j,S'_j)\) are determined as step \(1\), this value is at most \(1024\) under the constraints of the problem. This can be found relatively easily by considering how many distinct values are there in \(k_0,k_1,\ldots,k_N\).

The possible \(C'\) that can be transitioned from each \(C\) (and the number of \(X'\) achieving them) can be precalculated. Therefore, the number of computational operations required is, even evaluated naively, about\(1024\times 2^8\times 8\times 8=2^{24}\). Also, the number of transitions of the actual DP is at most \(30\times 1024\times 2^8\simeq 8\times 10^6\), so we may use an unordered_map and finish the execution well within the time limit.
Therefore, this algorithm has turned out fast enough for our problem.

Checking if the answer is Infinity

Finally, as we briefly mentioned at the last of step 1, we will describe how to determine if the answer is \(0\) or Infinity when there is \(A_j\) \((1\leq j\leq N)\) that does not appear in any of the \(M'\) equations. To go straight to the point, the answer is \(0\) if \(dp[30][(0,0,\ldots,0)]=0\), and Infinity otherwise. Here, note that even if \(dp[30][(0,0,\ldots,0)]\equiv 0 \pmod{998244353}\), the answer is still Infinity if \(dp[30][(0,0,\ldots,0)]>0\).

It is obvious that the answer is \(0\) if \(dp[30][(0,0,\ldots,0)]=0\), that is, there is no combination for the subset of \((A_1,\ldots,A_N)\) (appearing in the equations) satisfying the conditions. Otherwise, there is at least one \(A\) satisfying the condition. In this case, one can change the value of \(A_j\) not appearing in the equation to any non-negative integer while still satisfying the condition. Therefore, the answer exists infinitely in this case.

There are several approaches for implementation, including maintaining the flag indicating whether \(dp[i][S]>0\) separately from \(dp[i][S]\%998244353\), or defining \(T_i\) as the set of \((S,dp[i][S]\%998244353)\) for the set with \(dp[i][S]>0\), and checking if \(T_{30}\) contains \(((0,0,.\ldots,0),*)\). In any case, the effect to the complexity is extremely small.

Sample code in C++

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define rep(i, n) for(int i = 0; i < n; ++i)
#define N (int)8
#define MOD (ll)998244353

int n,k;
int d[N][N]; //whether A_j exist in the left side of i-th re-arranged constaint
ll s[N]; //S'_j

vector<int>a[1<<8]; //3k(max.24)bit
vector<ll>c[1<<8];  //count

void pre_calc(void){
	unordered_map<int,int>tmp[1<<8];
	rep(bits,1<<n){
		int x[8]={};
		int y=0,z=0;
		rep(i,k){
			rep(j,n){
				if(d[i][j]==1)x[i]+=(bits>>j)&1;
			}
		}
		rep(j,k){
			y|=(x[j]&1)<<j; //k bit
			z|=(x[j]>>1)<<(j*3); //3k bit
		}
		tmp[y][z]=tmp[y][z]+1;
	}
	rep(i,1<<k){
		unordered_map<int,int>::iterator itr=tmp[i].begin();
		while(itr!=tmp[i].end()){
			a[i].push_back((*itr).first);
			c[i].push_back((*itr).second);
			itr++;
		}
	}
	return;
}




int main(void){
	int tmpl,tmpr;
	ll tmps;
	int m;
	int base[N+1];
	ll offset[N+1];

	//receive input
	cin>>n>>m;

	rep(i,n+1){
		base[i]=i;
		offset[i]=0;
	}

	rep(i,m){
		cin>>tmpl>>tmpr>>tmps;
		tmpl--;
		tmps-=(tmpr-tmpl); //Ai: positive -> non-negative
		if(tmps<0){
			cout<<"0"<<endl;
			return 0;
		}
		if(base[tmpl]==base[tmpr]){
			if(offset[tmpr]-offset[tmpl]!=tmps){
				cout<<"0"<<endl;
				return 0;
			}
		}
		int overwrite_before, overwrite_after;
		ll add_offset;
		if(base[tmpl]<base[tmpr]){
			overwrite_before=base[tmpr];
			overwrite_after=base[tmpl];
			add_offset=offset[tmpl]-offset[tmpr]+tmps;
		}
		else{
			overwrite_before=base[tmpl];
			overwrite_after=base[tmpr];
			add_offset=offset[tmpr]-offset[tmpl]-tmps;
		}
		rep(j,n+1){
			if(base[j]==overwrite_before){
				base[j]=overwrite_after;
				offset[j]+=add_offset;
			}
		}
	}

	//set re-arranged constraints
	int x[30][8];  //x[i][j] i-th bit of S'_j
	bool used[8]={}; //check for the existence of un-constrained Ai
	k=0; //M'
	rep(i,N)rep(j,N)d[i][j]=0;
	rep(i,n){
		for(int j=i+1;j<=n;j++){
			if(base[i]==base[j]){
				if(offset[j]-offset[i]<0){
					cout<<"0"<<endl;
					return 0;
				}
				for(int ii=i;ii<j;ii++){
					d[k][ii]=1;
					used[ii]=true;
				}
				s[k]=offset[j]-offset[i];
				for(int ii=0;ii<30;ii++)x[ii][k]=(s[k]>>ii)&1;
				k++;
				break;
			}
		}
	}

	pre_calc();

	vector<int>dpkey={0}; //3k bit
	vector<ll>dpcnt={1};
	rep(i,30){
		int sz=dpkey.size();
		unordered_map<int,ll>mp;
		rep(j,sz){
			int y[8]={};
			rep(ii,k)y[ii]=(dpkey[j]>>(3*ii))&1;
			int pre=0; //3k bit
			rep(ii,k)pre|=(dpkey[j]>>1)&(3<<(3*ii));
			int add_key=0;//k bit
			rep(ii,k){
				add_key|=(x[i][ii]^y[ii])<<ii;
				if((x[i][ii]==0)&&(y[ii]==1))pre+=1<<(3*ii);
			}
			int sz2=a[add_key].size();
			rep(ii,sz2){
				mp[a[add_key][ii]+pre]=mp[a[add_key][ii]+pre]+(c[add_key][ii]*dpcnt[j]);
			}
		}
		dpkey.clear();
		dpcnt.clear();
		unordered_map<int,ll>::iterator itr=mp.begin();
		while(itr!=mp.end()){
			dpkey.push_back((*itr).first);
			dpcnt.push_back((*itr).second%MOD);
			itr++;
		}
	}

	//judge zero/non-zero and get remainder
	bool found=false;
	ll ans=0;
	int sz=dpkey.size();
	rep(i,sz){
		if(dpkey[i]==0){
			found=true;
			ans=dpcnt[i];
		}
	}
	if(found){
		rep(i,n){
			if(!used[i]){
				cout<<"Infinity"<<endl;
				return 0;
			}
		}
		cout<<ans<<endl;
	}
	else{
		cout<<0<<endl;
	}
	
	return 0;
}

posted:
last update: