ARC135 题解

为什么不写 AGC,因为我还不会 ARC

A - Floor, Ceil - Decomposition

  • 给定一个数 \(x\),你可以执行操作任意次。

  • 每次操作从中选出一个数 \(x\),将其拆分成 \(\lfloor \frac{x}{2} \rfloor\)\(\lceil \frac{x}{2} \rceil\)。求最后所有数的积的最大值。

  • \(1 \leq x \leq 10^{18}\)


\(x\leq 4\) 的时候不用再分,否则必须要分。

记忆化搜索。时间复杂度 \(O(\log x\log\log x)\)

#include<bits/stdc++.h>
using namespace std;
using namespace my_std;
#define mod 998244353
map<ll,ll> mp;
ll x;
ll f(ll x){
	if(x<=4) return x;
	if(mp.count(x)) return mp[x];
	return mp[x]=f(x/2)*f((x+1)/2)%mod;
}
int main(){
	x=read();
	write(f(x));
}

B - Sum of Three Terms

  • 给定一个长为 \(n\) 的序列 \(S\),要求构造一个长为 \(n+2\) 的非负整数序列 \(A\),使得 \(\forall i \in [1,n],A_i+A_{i+1}+A_{i+2}=S_i\),或判断无解。

  • \(1 \leq n \leq 3\times 10^5,0 \leq S_i \leq 10^9\)


如果 \(A_1,A_2,A_3\) 知道了,那么所有 \(A_i\) 都可以推出来,并且 \(A_{3k+1},A_{3k+2},A_{3k+3}\) 互不影响。所以先算出来 \(A_{3k+i}\)\(A_i\) 的差 \(B_{3k+i}\)

先根据 \(S_1\) 判断后面的 \(S_i\) 合不合法。因为要求 \(A\) 非负,所以需要满足 \(A_i+B_{3k+i} \geq 0\),即 \(A_i \geq -B_{3k+i}\)

得出 \(A_1,A_2,A_3\) 的最小值后再判断合不合法,然后随便构造。

时间复杂度 \(O(n)\)

#include<bits/stdc++.h>
using namespace std;
using namespace my_std;
ll n,s[300030],a[300030],minn[4];
int main(){
	n=read();
	fr(i,1,n) s[i]=read();
	fr(i,1,n-1) a[i+3]=a[i]+s[i+1]-s[i];
	fr(i,1,n){
		if(s[i]!=(s[1]+a[i]+a[i+1]+a[i+2])){
			pf("No");
			return 0;
		}
	}
	fr(i,1,3) minn[i]=inf;
	for(ll i=1;i<=(n+2);i+=3) minn[1]=min(minn[1],a[i]);
	for(ll i=2;i<=(n+2);i+=3) minn[2]=min(minn[2],a[i]);
	for(ll i=3;i<=(n+2);i+=3) minn[3]=min(minn[3],a[i]);
	if((-minn[1]-minn[2]-minn[3])>s[1]){
		pf("No");
		return 0;
	}
	a[1]=-minn[1];
	a[2]=-minn[2];
	a[3]=s[1]-a[1]-a[2];
	fr(i,1,n-1) a[i+3]=a[i]+s[i+1]-s[i];
	pf("Yes\n");
	fr(i,1,n+2) writesp(a[i]);
}

C - XOR to All

  • 给定一个长度为 \(n\) 的序列 \(a\),你可以进行若干次操作。

  • 每次操作你可以从 \(a\) 当中选定一个数,并将 \(a\) 中所有数异或上它。求最后 \(\displaystyle\sum_{i=1}^{n}{a_i}\) 的最大值。

  • \(1 \leq n \leq 3 \times 10^5,0 \leq a_i < 2^{30}\)


首先可以发现,无论执行多少次操作,都等价于只执行最后那个操作。

证明

WLOG,我们先后选择第 \(n-1\) 个位置上的数和第 \(n\) 个位置上的数。

那么第一次操作后,序列变成了

\[a_1 \bigoplus a_{n-1},a_2 \bigoplus a_{n-1} \ldots a_{n-2} \bigoplus a_{n-1},0,a_{n-1} \bigoplus a_n \]

第二次操作后,序列变成了

\[a_1 \bigoplus a_{n},a_2 \bigoplus a_{n} \ldots a_{n-2} \bigoplus a_{n},a_{n-1} \bigoplus a_{n},0 \]

所以枚举要选的数,然后计算答案。计算答案直接按位考虑,看第 \(i\) 位有多少个数与选的数相反。

注意可以不选。时间复杂度 \(O(n\log A)\)

#include<bits/stdc++.h>
using namespace std;
using namespace my_std;
ll n,a[300030][31],sum[31],ans;
int main(){
	n=read();
	fr(i,1,n){
		ll x=read();
		ans+=x;
		fr(j,0,30) if(x&(1ll<<j)) a[i][j]=1;
		fr(j,0,30) sum[j]+=a[i][j];
	}
	fr(i,1,n){
		ll res=0;
		fr(j,0,30){
			if(a[i][j]) res+=(1ll<<j)*(n-sum[j]);
			else res+=(1ll<<j)*sum[j];
		}
		ans=max(ans,res);
	}
	write(ans);
}

前三题切的不必大声喊叫,看看就好。

后三题切的就可以出门左转了。


D - Add to Square

  • 给定一个 \(n\times m\) 的网格,每个格子有一个整数 \(A_{i,j}\),你可以执行任意多次操作。

  • 每次操作选定一个位置 \((i,j)(1 \leq i < n,1 \leq j < m)\),再选定一个整数 \(x\),将 \(A_{i,j},A_{i,j+1},A_{i+1,j}\)\(A_{i+1,j+1}\)\(x\)。你要使得最终的 \(\displaystyle\sum_{i=1}^{n}\sum_{j=1}^{m}{|A_{i,j}|}\) 最小。

  • \(2 \leq n,m \leq 500,|A_{i,j}| \leq 10^9\)


不妨设最终的网格为 \(B\)

对于每一行,因为每次只会同时给相邻两个数加 \(x\),说明其交替和是不会变的,即 \(\displaystyle\sum_{j=1}^{m}{A_{i,j}\times (-1)^j}\) 不变。每一列同理。

所以我们得到了 \(B\) 的一个必要条件,就是每一行、每一列的交替和与 \(A\) 相同。

同时,这也是 \(B\) 的一个充分条件。

证明

要证它是充分条件,相当于证明每一个交替和与 \(A\) 相同的 \(B\) 都可以通过若干次操作得到。

由题目易知,能从 \(A\)\(B\),也能从 \(B\)\(A\)。那我们尝试将 \(B\) 还原成 \(A\)

\(B\) 网格从上到下,从左到右进行操作,每次将左上角 \(B_{i,j}\) 还原成 \(A_{i,j}\)。这样我们就将所有 \(1 \leq i < n,1 \leq j < m\)\((i,j)\) 还原了。

至于最后一行,因为我们操作后 \(B\) 的交替和是不变的,所以可以通过交替和与前 \(n-1\) 个数来得到第 \(n\) 个数究竟是什么。最后一列同理。

因为 \(B\)\(A\) 的交替和相同,所以最后一行与最后一列也与 \(A\) 相同。

交替和这种东西有点难搞,所以先将每个 \(A_{i,j}\) 变成 \(A_{i,j} \times (-1)^{i+j}\) ,然后我们改一下题目:

给定两个序列 \(\{x_1,\ldots,x_n\}\),\(\{y_1,\ldots,y_m\},\sum{x_i}=\sum{y_j}\),你要构造一个矩阵 \(B\),使得第 \(i\) 行的和是 \(x_i\),第 \(j\) 列的和是 \(y_j\)。求 \(\sum{|B_{i,j}|}\) 的最小值。

先将 \(B\) 中的元素全部设为 \(0\),然后一个一个在 \((i,j)\) 上加一些值,题目变成了:

给定两个序列 \(\{x_1,\ldots,x_n\}\),\(\{y_1,\ldots,y_m\},\sum{x_i}=\sum{y_j}\),你可以进行任意次操作。
每次操作 \((i,j,x)\) 表示让 \(x_i\)\(y_j\)\(x\),代价为 \(|x|\)。你需要让所有 \(x\)\(y\) 变为 \(0\),并且求代价最小值。

首先有个很显然的下界:\(Ans \geq \max(\sum{|x_i|},\sum{|y_j|})\)。下面我们通过构造操作证明答案可以取到下界。

当存在 \(x_i\)\(y_j\) 正负性相同时,可以将它们同时减(加)一,如此循环下去,这肯定是最优的。

当存在 \(x_i > 0\)\(x_j < 0\) 时,可以先将 \(x_i\)\(y_1\) 减一,再把 \(x_j\)\(y_1\) 加一,这样也可以紧贴下界。对于 \(y\) 同理。

通过上述操作,我们将所有 \(x_i\) 的正负性统一了,也将 \(y_j\) 的正负性统一了,而且 \(x_i\)\(y_j\) 正负性相反。又因为 \(\sum{x_i}=\sum{y_j}\),所以 \(x\)\(y\) 只能全是 \(0\)。这就符合条件了。

时间复杂度 \(O(n^3)\)

#include<bits/stdc++.h>
using namespace std;
using namespace my_std;
ll n,m,a[550][550],x[550],y[550],b[550][550];
ll pos1[550],pos2[550],cnt1=0,cnt2=0,ans=0;
void solve(){
	fr(i,1,n) if(x[i]>0) pos1[++cnt1]=i;
	fr(i,1,m) if(y[i]>0) pos2[++cnt2]=i;
	while(cnt1&&cnt2){
		ll tmp=min(x[pos1[cnt1]],y[pos2[cnt2]]);
		b[pos1[cnt1]][pos2[cnt2]]+=tmp;
		x[pos1[cnt1]]-=tmp;
		y[pos2[cnt2]]-=tmp;
		if(!x[pos1[cnt1]]) cnt1--;
		if(!y[pos2[cnt2]]) cnt2--;
	}
	cnt1=cnt2=0;
	fr(i,1,n) if(x[i]<0) pos1[++cnt1]=i;
	fr(i,1,m) if(y[i]<0) pos2[++cnt2]=i;
	while(cnt1&&cnt2){
		ll tmp=min(-x[pos1[cnt1]],-y[pos2[cnt2]]);
		b[pos1[cnt1]][pos2[cnt2]]-=tmp;
		x[pos1[cnt1]]+=tmp;
		y[pos2[cnt2]]+=tmp;
		if(!x[pos1[cnt1]]) cnt1--;
		if(!y[pos2[cnt2]]) cnt2--;
	}
	cnt1=cnt2=0;
	fr(i,1,n){
		if(x[i]>0) pos1[++cnt1]=i;
		if(x[i]<0) pos2[++cnt2]=i;
	}
	while(cnt1&&cnt2){
		ll tmp=min(x[pos1[cnt1]],-x[pos2[cnt2]]);
		b[pos1[cnt1]][1]+=tmp;
		b[pos2[cnt2]][1]-=tmp;
		x[pos1[cnt1]]-=tmp;
		x[pos2[cnt2]]+=tmp;
		if(!x[pos1[cnt1]]) cnt1--;
		if(!x[pos2[cnt2]]) cnt2--;
	}
	cnt1=cnt2=0;
	fr(i,1,m){
		if(y[i]>0) pos1[++cnt1]=i;
		if(y[i]<0) pos2[++cnt2]=i;
	}
	while(cnt1&&cnt2){
		ll tmp=min(y[pos1[cnt1]],-y[pos2[cnt2]]);
		b[1][pos1[cnt1]]+=tmp;
		b[1][pos2[cnt2]]-=tmp;
		y[pos1[cnt1]]-=tmp;
		y[pos2[cnt2]]+=tmp;
		if(!y[pos1[cnt1]]) cnt1--;
		if(!y[pos2[cnt2]]) cnt2--;
	}
}
int main(){
	n=read();
	m=read();
	fr(i,1,n) fr(j,1,m) a[i][j]=read();
	fr(i,1,n) fr(j,1,m) if((i+j)&1) a[i][j]=-a[i][j];
	fr(i,1,n) fr(j,1,m) x[i]+=a[i][j];
	fr(j,1,m) fr(i,1,n) y[j]+=a[i][j];
	solve();
	fr(i,1,n) fr(j,1,m) if((i+j)&1) b[i][j]=-b[i][j];
	fr(i,1,n) fr(j,1,m) ans+=abs(b[i][j]);
	writeln(ans);
	fr(i,1,n){
		fr(j,1,m) writesp(b[i][j]);
		enter;
	}
}

E - Sequence of Multiples

  • 给定 \(a_1\),你要构造一个长度为 \(n\) 的序列 \(a_n\),使得其严格递增且 \(\forall i \in [1,n],i \mid a_i\)。求 \(\displaystyle\sum_{i=1}^{n}{a_i}\) 的最小值,结果对 \(998244353\) 取模。

  • \(1 \leq n \leq 10^{18},1 \leq a_1 \leq 10^{18}\),有不超过 \(10\) 组询问。


先设 \(a_i=p_i\times i\),那么 \(a_i < a_{i+1} \Rightarrow p_{i+1}=p_i-\lceil \frac{p_i}{i+1} \rceil+1\),所以 \(p_i\) 单调不升。

因为 \(p_{i}-p_{i+1}=\lceil \frac{p_i}{i+1} \rceil-1\),所以又有 \(p_{i}-p_{i+1}\) 单调不升。

我们将相同的 \(p_i-p_{i+1}\) 看成一段,假设 \(i \in [s,t],p_i-p_{i+1}=\Delta p\)。由于它是等差数列,那么每一项的 \(p\)\(\displaystyle\sum_{i=s}^{t}{p_i\times i}\) 都可以快速算出来。

别告诉我你不会求和

\[p_i=p_s-(i-s)\Delta p \]

\[\displaystyle\sum_{i=s}^{t}p_i\times i \]

\[=\sum_{i=s}^{t}{[p_s-(i-s)\Delta p]\times i} \]

\[=\sum_{i=s}^{t}{p_s\times i-(i-s)\times i \times \Delta p} \]

\[=\sum_{i=s}^{t}{p_s\times i}-\sum_{i=s}^{t}{[(i^2\times \Delta p)-(i\times s \times \Delta p)]} \]

\[=\frac{p_s(s+t)(t-s+1)}{2}-\sum_{i=s}^{t}{i^2\times \Delta p}+\sum_{i=s}^{t}{i\times s \times \Delta p} \]

\[=\frac{(p_s+s\times \Delta p)(s+t)(t-s+1)}{2}-\Delta p \times \frac{t(t+1)(2t+1)-(s-1)s(2s-1)}{6} \]

如何通过 \(s\) 找到 \(t\) 呢?因为 \(p_{t+1}-p_{t+2}<\Delta p\),所以可以推出来 \(t=\lceil \frac{p_s+(s-3)\Delta p}{2\Delta p} \rceil-1\)。于是我们可以在 \(O(1)\) 的时间内找到下一段并算出答案。

同时,通过推导也可以证明出最多有 \(2\lceil \sqrt[3]{a_1} \rceil\) 段。

证明

首先,\(a_i-a_{i-1} \leq i\),否则与 \(a_i\) 最小矛盾。

所以 \(a_n \leq a_1+\frac{(n+2)(n-1)}{2} <a_1+n^2(n \geq 2)\)

\(\Rightarrow p_n < \frac{a_1}{n}+n\)

\(n=\sqrt[3]{a_1}\),则 \(p_n < n^2+n\)

因为 \(p_n-p_{n+1}=\lceil \frac{p_n}{n+1} \rceil-1<\lceil \frac{n^2+n}{n+1} \rceil-1 < n\)

所以在 \(n\) 后面最多存在 \(n\) 段。而在 \(n\) 前面最多存在 \(n\) 段,故最多有 \(2n=2\lceil \sqrt[3]{a_1} \rceil\) 段。

时间复杂度为 \(O(\sqrt[3]{a_1})\)

#include<bits/stdc++.h>
#define ll long long
#define fr(i,x,y) for(register ll i=(x);i<=(y);i++)
#define il inline
#define mod 998244353
using namespace std;
int t,inv2=(mod+1)/2,inv6=(mod+1)/6,ans=0;
ll n,x,tmp1,tmp2,tmp3;
il void calc(ll s,ll t,ll p,ll delta){
	if(s>t) return;
	if(s==t){
		ans=(ans+(p%mod)*(s%mod)%mod)%mod;
		return;
	}
	tmp1=(p+(s%mod)*(delta%mod)%mod)%mod*((s+t)%mod)%mod*((t-s+1)%mod)%mod*inv2%mod;
	tmp2=t%mod*((t+1)%mod)%mod*((2*t+1)%mod)%mod;
	tmp3=s%mod*((s-1)%mod)%mod*((2*s-1)%mod)%mod;
	tmp2-=tmp3;
	if(tmp2<0) tmp2+=mod;
	tmp2=tmp2*inv6%mod;
	tmp2=tmp2*(delta%mod)%mod;
	tmp1-=tmp2;
	if(tmp1<0) tmp1+=mod;
	ans+=tmp1;
	if(ans>=mod) ans-=mod;
}
il ll ceill(ll x,ll y){
	return (x+y-1)/y;
}
int main(){
	scanf("%d",&t);
	while(t--){
		ans=0;
		scanf("%lld %lld",&n,&x);
		if(n==1){
			printf("%lld\n",x%mod);
			continue;
		}
		ll s=1,delta=ceill(x,2)-1,p=x;
		while(s<=n&&delta){
			ll t=min(n,ceill(p+(s-3)*delta,2*delta));
			calc(s,t,p,delta);
			p=p-(t+1-s)*delta;
			s=t+1;
			delta=ceill(p,s+1)-1;
		}
		calc(s,n,p,delta);
		printf("%d\n",ans);
	}
}

F - Delete 1, 4, 7, ...

  • 给定一个正整数 \(n\),初始有一个序列 \({1,2,\ldots,n}\),你需要进行 \(k\) 次操作。

  • 每次操作,你要将位置\(1,4,7,\ldots,3i+1(i \in \mathbb{N})\) 的数删除。求最后剩下的数的和。

  • \(1 \leq n \leq 10^{14},1 \leq k \leq 100\)


\(f(i)=\lfloor \frac{3i+1}{2} \rfloor\),那么 \(f(i)\) 其实就是第一次操作后,第 \(i\) 个位置的数。同理,\(k\) 次操作后,位置为 \(i\) 的数就是 \(f(f(\cdots f(f(i)) \cdots))=f^{k}(i)\)

不妨设 \(cnt_k\)\(k\) 次操作后剩下的数的个数,这个很容易递推出来,那么最后相当于求 \(\displaystyle\sum_{i=1}^{cnt_k}{f^k(i)}\)。如果我们采用暴力递推的方式求出 \(f^k(i)\),那么我们会得到一个“优秀”的复杂度:\(O(k\times cnt_k)\)

因为我们只需处理出来前 \(cnt_k\) 个数的 \(f\),而 \(cnt_k \leq n\times (\frac{2}{3})^{k}\),所以时间复杂度大约是 \(O(nk(\frac{2}{3})^k)\)所以这道F就被我们切了

实际上,这种做法只在 \(k\) 很大的时候有用,当 \(k\) 小一点的时候我们要另寻他法。我们现在只找到了 \(f^k\)\(f^{k-1}\) 之间的关系,那 \(f^k(i)\)\(f^k(j)\) 之间有什么关系呢?

有一个直觉上很对的等式:\(f^k(n+2^k)=f^k(n)+3^k\)

证明

\(k=1\) 时,根据题意显然得证。

\(k>1\) 时:

\[f^k(n+2^k) \]

\[=f^{k-1}(f(n+2^k)) \]

\[=f^{k-1}(\lfloor \frac{3(n+2^k)+1}{2} \rfloor) \]

\[=f^{k-1}(\lfloor \frac{3n+1}{2}\rfloor+3\times 2^{k-1}) \]

\[=f^{k-1}(f(n)+3\times 2^{k-1}) \]

\[=f^{k}(n)+3\times 3^{k-1} \]

\[=f^{k}(n)+3^k \]

由数学归纳法得证。

所以我们只需要处理出前面 \(2^k\)\(f^k\) 值,时间复杂度降到了 \(O(k\times 2^k)\),但还是不够。

考虑将 \(f^k(i)\) 拆成 \(f^x(f^y(i)),x+y=k\),那么 \(f^k(i+2^yj)=f^x(f^y(i+2^yj))=f^x(f^y(i)+3^yj)\)

枚举 \(i \in [1,2^y]\),那么相当于要算 \(\displaystyle\sum_{j}{f^x(f^y(i)+3^yj)}\),因为 \(i+2^yj \leq cnt_k\),所以 \(j\) 的上界为 \(\lfloor \frac{cnt_k-i}{2^y} \rfloor+1\)(要保证所有数都被算到,而且多出来的部分本来就是 \(0\),不用管)。

如何快速计算?设 \(g(a,i)\)\(\displaystyle\sum_{j=0}^{2^i-1}{f^x(a+3^yj)}\),那么 \(g(a,i)=g(a,i-1)+g(a+3^y2^{i-1},i-1)\),最后 \(g(a,0)=f^x(a)\)

还有一个小优化,就是当 \(a>2^x\) 的时候,递归到 \(g((a-1)\mod 2^x+1,i)\),最后在答案上面加上剩下的 \(3^x\)。可用记搜优化。

\(j\) 的上界 \(\lceil \frac{cnt_k-i}{2^y} \rceil\) 二进制拆分,如果第 \(p\) 位是 \(1\) 就计算对应的 \(g\),然后在原来的 \(a\) 加上 \(3^y2^p\)。原来的 \(a\) 其实就是 \(f^y(i)\)

所以这部分的时间复杂度大概是 \(O(2^y\log n+2^x k)\),当 \(x=y=\frac{k}{2}\) 时可以做到 \(O((k+\log n)2^{k/2})\)。于是我们在 \(k \leq 40\) 时使用此算法,在 \(k > 40\) 时使用上面的暴力。

#include<bits/stdc++.h>
using namespace std;
using namespace my_std;
#define mod 998244353
ll n,k,cnt[110],X,Y,pw3[110],mp[1100000][51],ans=0;
ll f(ll x,ll k){
	fr(i,1,k) x=(3*x+1)/2;
	return x;
}
void sub(){
	fr(i,1,cnt[k]) ans=(ans+f(i,k)%mod)%mod;
	write(ans);
}
il ll ceill(ll x,ll y){
	return (x+y-1)/y;
}
ll g(ll a,ll i){
	if(a>(1ll<<X)){
		ll tmp=((a-1)/(1ll<<X))%mod;
		return (g((a-1)%(1ll<<X)+1,i)+tmp*(pw3[X]%mod)%mod*((1ll<<i)%mod)%mod)%mod;
	}
	if(!i) return f(a,X)%mod;
	if(mp[a][i]) return mp[a][i];
	return mp[a][i]=(g(a,i-1)+g(a+pw3[Y]*(1ll<<(i-1)),i-1))%mod;
}
int main(){
	n=read();
	k=read();
	cnt[0]=n;
	fr(i,1,k) cnt[i]=(2*cnt[i-1])/3;
	if(k>40){
		sub();
		return 0;
	}
	X=k/2;
	Y=k-X;
	pw3[0]=1;
	fr(i,1,30) pw3[i]=pw3[i-1]*3;
	fr(i,1,min(cnt[k],1ll<<Y)){
		ll A=f(i,Y),maxx=(cnt[k]-i)/(1ll<<Y)+1;
		fr(j,0,50){
			if(maxx&(1ll<<j)){
				ans=(ans+g(A,j))%mod;
				A+=pw3[Y]*(1ll<<j);
			}
		}
	}
	write(ans);
}
posted @ 2022-02-17 08:20  AFewSuns  阅读(414)  评论(0编辑  收藏  举报