其他分享
首页 > 其他分享> > ARC135 题解

ARC135 题解

作者:互联网

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

A - Floor, Ceil - Decomposition


当 \(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


如果 \(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


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

证明

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


不妨设最终的网格为 \(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_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, ...


设 \(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(\sum 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\) 的上界为 \(\lceil \frac{cnt_k-i}{2^y} \rceil\)(如果向下取整,那么后面有些数可能没有算到;如果向上取整,多出来的部分本来就是 \(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\) 时使用上面的暴力。

还没过

标签:ARC135,frac,题解,sum,times,leq,ll,mod
来源: https://www.cnblogs.com/AFewSuns/p/15897764.html