Loading

Codeforces 1734 / Codeforces Round #822 (Div. 2)

Codeforces Round #822 (Div. 2)

Problem A Select Three Sticks

题意

给定 \(n\) 根木棍,第 \(i\) 根长度为 \(a_i\)。每次操作可以选一根木棍使得其长度增加 \(1\) 或减少 \(1\),但不能变成 \(0\) 及以下。

问至少要多少次操作才能得到一个等边三角形。

多组数据,数据组数 \(1 \leq T \leq 100\)\(3 \leq n,\sum n \leq 300\)

题解

注意到肯定排序后取相邻的 \(3\) 个。

Problem B Bright, Nice, Brilliant

题意

给定 \(n\) 行的格子,第 \(i\) 行有 \(i\) 个格子。称格子 \(A\) 能到格子 \(B\),当且仅当 \(A\) 可以通过往右或者往右下方走若干步(可以为 \(0\))到达格子 \(B\)

你现在需要将某些格子加个 buff。记 \(f(A)\) 表示被加了 buff 并能到达 \(A\) 的格子的数量。你需要使得每一行的格子的 \(f\) 值完全相同。

多组数据,数据组数 \(1 \leq T \leq 100\)\(1 \leq n,\sum n \leq 500\)

题解

把每一行第一个和最后一个格子加上 buff 即可。

容易证明这是上界。

Problem C Removing Smallest Multiples

题意

给定 \(S=\{1,2,\cdots,n\}\) 和它的子集 \(T\)。可以花费 \(x\) 的代价删除 \(S\)\(x\) 的最小倍数,问至少要花费多少代价才能把 \(S\) 变成 \(T\)

多组数据,数据组数 \(1 \leq T \leq 10^4\)\(1 \leq n,\sum n \leq 10^6\)

题解

考虑从小到大枚举 \(x\),然后看 \(x\) 能删掉哪些。肯定只能挨着删 \(x,2x,\cdots\),如果中间某一个元素在 \(T\) 中了就 break。

注意区分一下,如果 \(x\) 的某个倍数曾经被删过,但不在 \(T\) 中,这是 ok 的可以接着删。

int main(void){
	int T=read();
	while(T--){
		n=read();
		scanf("%s",s+1);
		long long ans=0;
		for(int i=1;i<=n;++i){
			if(s[i]=='1') continue;
			if(s[i]=='0') ans+=i,s[i]='1';
			for(int j=2*i;j<=n;j+=i) if(s[j]=='1') break; else if(s[j]) ans+=i,s[j]=0;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

Problem D Slime Escape

题意

给定长度为 \(n\) 的数组 \(a_1,a_2,\cdots,a_n\)(元素可以为负)和起点 \(s\),每经过一个位置你的健康值就会加上那个位置的权值,然后该位置权值变为 \(0\)。问能否在健康值非负的情况下到达 \(0\) 或者 \(n+1\)

数据组数 \(1 \leq T \leq 10^4\)\(1 \leq n,\sum n \leq 10^6\)

题解

我们规定一个初始方向。肯定是贪心地往前走,能走出去就行,如果不能走出去,设当前在 \(c\) 最远能走到 \(d\),那么我们在 \([c,d]\) 中选一个位置停下使得健康值最大,然后换一个方向继续。

选一种你喜欢的数据结构进行模拟即可。

# include <bits/stdc++.h>
# define int long long
const int N=200010,INF=0x3f3f3f3f;
typedef long long ll;
ll pre[N],suf[N];
int a[N];
int T,n,k;
int logt[N];
struct STable{
	ll STmin[N][21],STmax[N][21],len;
	int mpos[N][21];
	inline void init(int siz,ll a[]){
		len=siz;
		for(int i=1;i<=siz;++i) STmin[i][0]=STmax[i][0]=a[i],mpos[i][0]=i;
		for(int j=1;(1<<j)<=siz;++j){
			for(int i=1;i+(1<<j)-1<=siz;++i){
				STmin[i][j]=std::min(STmin[i][j-1],STmin[i+(1<<(j-1))][j-1]);
				int lv=STmax[i][j-1],rv=STmax[i+(1<<(j-1))][j-1];
				if(lv>rv) STmax[i][j]=lv,mpos[i][j]=mpos[i][j-1];
				else STmax[i][j]=rv,mpos[i][j]=mpos[i+(1<<(j-1))][j-1];
			}
		}
		return;
	}
	inline int qmax(int l,int r){
		int len=logt[r-l+1];
		return (STmax[l][len]>STmax[r-(1<<len)+1][len])?mpos[l][len]:mpos[r-(1<<len)+1][len];
	}
	inline int qmin(int l,int r){
		int len=logt[r-l+1];
		return std::min(STmin[l][len],STmin[r-(1<<len)+1][len]);
	}
}Q[2];

inline int read(void){
	int res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-')f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}

signed main(void){
	for(int i=2;i<=N-5;++i) logt[i]=logt[i>>1]+1;
	T=read();
	while(T--){
		n=read(),k=read(),suf[n+1]=0;
		for(int i=1;i<=n;++i) a[i]=read();
		for(int i=1;i<=n;++i) pre[i]=pre[i-1]+a[i];
		for(int i=n;i;--i) suf[i]=suf[i+1]+a[i];
		Q[0].init(n,pre),Q[1].init(n,suf);
		int L=k,R=k,cur=a[k];
		for(int i=1;i<=n+10;++i){
			int l=1,r=L-1,ans=L;
			while(l<=r){
				int mid=(l+r)>>1;
				if(Q[1].qmin(mid,L-1)-suf[L]+cur>=0) ans=mid,r=mid-1;
				else l=mid+1;
			}
			if(ans==1){
				puts("YES");
				goto End;
			}
			int pos=Q[1].qmax(ans,L);
			cur+=suf[pos]-suf[L],L=pos;
			l=R+1,r=n,ans=R;
			while(l<=r){
				int mid=(l+r)>>1;
				if(Q[0].qmin(R+1,mid)-pre[R]+cur>=0) ans=mid,l=mid+1;
				else r=mid-1;
			}
			if(ans==n){
				puts("YES");
				goto End;
			}
			pos=Q[0].qmax(R,ans);
			cur+=pre[pos]-pre[R],R=pos;
		}
		
		
		L=k,R=k,cur=a[k];
		for(int i=1;i<=n+10;++i){
			int l=R+1,r=n,ans=R;
			while(l<=r){
				int mid=(l+r)>>1;
				if(Q[0].qmin(R+1,mid)-pre[R]+cur>=0) ans=mid,l=mid+1;
				else r=mid-1;
			}
			if(ans==n){
				puts("YES");
				goto End;
			}
			int pos=Q[0].qmax(R,ans);
			cur+=pre[pos]-pre[R],R=pos;
			
			l=1,r=L-1,ans=L;
			while(l<=r){
				int mid=(l+r)>>1;
				if(Q[1].qmin(mid,L-1)-suf[L]+cur>=0) ans=mid,r=mid-1;
				else l=mid+1;
			}
			if(ans==1){
				puts("YES");
				goto End;
			}
			pos=Q[1].qmax(ans,L);
			cur+=suf[pos]-suf[L],L=pos;
		}
		puts("NO");
		End:;
	}

	return 0;
}

Problem E Rectangular Congruence

题意

给定 \(n\) 和长度为 \(n\) 的序列 \(b\),你需要构造一个 \(n \times n\) 的矩阵 \(a\),满足以下条件:

  • \(0 \leq a_{i,j} <n\)
  • \(a_{i,i}=b_i\)
  • 对于 \(r_1<r_2,c_1<c_2\),有 \(a_{r_1,c_1}+a_{r_2,c_2} \not \equiv a_{r_1,c_2}+a_{r_2,c_1} \pmod n\)

\(2 \leq n < 350\)

题解

首先注意到,往某一行和某一列上加一个值不影响限制 \(3\),于是我们可以忽略掉限制 \(2\),等构造完了再往某几行加一个值使得对角线满足限制。

事实上,\(a_{i,j}=ij\) 就是一种合法的构造。对于 \(r_1<r_2,c_1<c_2\),有

\[r_1 \neq r_2 \pmod n \\ r_1(c_1-c_2) \not \equiv r_2(c_1-c_2) \pmod n \\ r_1c_1+r_2c_2 \not \equiv r_1c_2+r_2c_1 \pmod n \\ \]

证毕。

更为一般地,\(i^2,j^2,ij,i,j,1\) 的任意线性组合都是一组合法解。我们可以往对应的行或列加上或减去若干个 \(i^2,j^2,i,j,1\) 使得这组构造变成 \(a_{i,j}=ij\)

int main(void){
	n=read();
	for(int i=1;i<=n;++i) b[i]=read();
	for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) a[i][j]=i*j%n;
	for(int i=1;i<=n;++i){
		if(a[i][i]!=b[i]){
			int det=b[i]-a[i][i];
			for(int j=1;j<=n;++j) a[i][j]=(a[i][j]+det+n)%n;
		}
	}
	for(int i=1;i<=n;++i) for(int j=1;j<=n;++j) printf("%d%c",a[i][j]," \n"[j==n]);
	return 0;
}

Problem F Zeros and Ones

题意

有一个无限长的 01 序列 \(S\),按照如下方式构造:

  • 初始 \(S=\texttt 0\)
  • 每次操作将 \(S\) 按位取反后写在 \(S\) 后面。前几次操作:\(\newcommand\t[1]{\texttt{#1}} \t 0 \to \t{01} \to \t{0110} \to \t{01101001}\to \cdots\)

现在给出 \(n,m\),问 \(S[0,m-1]\)\(S[n,n+m-1]\) 有多少位不同。

多组数据,数据组数 \(1 \leq T \leq 100\)\(1 \leq n,m \leq 10^{18}\)

题解

注意到 \(S\) 的意义。\(S_i\) 表示 \(i\) 二进制位 \(1\) 的个数的奇偶性。注意到 \(T\) 很小,说明单组数据不一定是 \(O( \log n)\) 或者 \(O(1)\)

考虑数位 DP。我们应该计算 \(x(0 \leq x < m)\)\(x+n\) 在二进制下 \(1\) 个数的奇偶性不同的 \(x\) 的数量,也即:\(\operatorname{popcount}(x)+\operatorname{popcount}(x+n)\) 是奇数的 \(x\) 的数量。按照数位 DP 的惯例,我们需要知道当前处在的位数 \(i\),并且要知道当前是否顶到了上界。同时,我们要记录当前的 \(\operatorname{popcount}\) 的奇偶性。因为有 \(x+n\) 这样的存在,所以我们要处理进位,故还需要记录当前 \(x+n\) 中连续的 \(1\) 的数量。

\(\newcommand\op[1]{\operatorname {#1}}f(i,\op{up},\op{sum},\op{ones})\) 表示上述状态。枚举当前位可以选的值,设当前位值为 \(a\)\(n\) 的对应位值为 \(b\)\(\operatorname{nup}\) 表示这一位选完之后的 \(\operatorname{up}\)。下面的 \(\operatorname{sum}\) 默认对 \(2\) 取模。

  • \(a=0,b=0\):则 \(\newcommand\op[1]{\operatorname {#1}}f(i,\op{up},\op{sum},\op{ones})\) 转移到 \(\newcommand\op[1]{\operatorname {#1}}f(i-1,\op{nup},\op{sum},\op{0})\)
  • \(a=0,b=1\):则 \(\newcommand\op[1]{\operatorname {#1}}f(i,\op{up},\op{sum},\op{ones})\) 转移到 \(\newcommand\op[1]{\operatorname {#1}}f(i-1,\op{nup},\op{sum}+1,\op{ones}+1)\)
  • \(a=1,b=0\):则 \(\newcommand\op[1]{\operatorname {#1}}f(i,\op{up},\op{sum},\op{ones})\) 转移到 \(\newcommand\op[1]{\operatorname {#1}}f(i-1,\op{nup},\op{sum}+2,\op{ones}+1)\)
  • \(a=1,b=1\):则 \(\newcommand\op[1]{\operatorname {#1}}f(i,\op{up},\op{sum},\op{ones})\) 转移到 \(\newcommand\op[1]{\operatorname {#1}}f(i-1,\op{nup},\op{sum}-\op{ones}+1+1,\op{ones})\),此时进位了,\(x+n\) 中连续的 \(1\) 变为了 \(1\) 个,故减少了 \(\operatorname{ones}-1\)\(1\)。同时 \(x\) 也多了一个 \(1\)

边界:\(i=0\) 时,如果 \(\operatorname{up} = 0,\operatorname{sum}=1\) 则返回 \(1\),否则返回 \(0\)

# include <bits/stdc++.h>

const int N=70,INF=0x3f3f3f3f;

typedef long long ll;

ll dp[N][N][2][2];// dp[i][j][0/1][0/1]: 高 i 位有 j 个尾随 1,和的奇偶性,是否顶上界 的方案数
int mp[N],np[N];
const int MAX=62;

inline ll read(void){
	ll res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-')f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}
ll n,m;
inline void par(void){
	for(int i=MAX;i>=0;--i) mp[i]=((m>>i)&1),np[i]=((n>>i)&1);
	return;
}
ll dfs(int i,int tra,int sum,bool u){
	if(i<0){
		return (sum&&!u);
	}
	ll &cur=dp[i][tra][sum][u];
	if(~cur) return cur;
	cur=0;
	for(int v=0;v<=1;++v){
		if(u&&v>mp[i]) break;
		int s=np[i]+v;
		bool nu=u&&(v==mp[i]);		
		if(s==0) cur+=dfs(i-1,0,sum,nu);
		if(s==1){
			if(np[i]) cur+=dfs(i-1,tra+1,1-sum,nu);
			else cur+=dfs(i-1,tra+1,sum,nu);
		}
		if(s==2) cur+=dfs(i-1,0,(sum+tra)%2,nu); // = (sum - tra + 1 + 1) % 2
	}
	return cur;
}

signed main(void){
	int T=read();
	while(T--){
		n=read(),m=read();
		par(),memset(dp,-1,sizeof(dp)),printf("%lld\n",dfs(MAX,0,0,true));
	}

	return 0;
}

posted @ 2022-10-01 15:14  Meatherm  阅读(32)  评论(0编辑  收藏  举报