「Codeforces Round」#811 (Div 3)

CF1714.

最近摸得有点厉害,主要是被自己菜到了,心态有点差……

老年人也就看看 Div 3 了。

A. Everyone Loves to Sleep

转化成分钟乱搞即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int t, n, H, M, D, ans, h[15], m[15], d[15];
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
void solve() {
	n=read(), H=read(), M=read();
	D=H*60+M;
	ans=1<<30;
	for(int i=1;i<=n;++i) {
		h[i]=read(), m[i]=read();
		d[i]=h[i]*60+m[i];
		if(d[i]<D) d[i]+=24*60;
	}
	for(int i=1;i<=n;++i) ans=min(ans,d[i]-D);
	printf("%lld %lld\n",ans/60,ans%60);
}
signed main() {
	t=read();
	while(t--) solve();
}

B. Remove Prefix

从后往前寻找第一个重复数字出现的位置即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int t, n, ans, a[N];
map<int,int> p;
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
void solve() {
	n=read();
	p.clear(), ans=0;
	for(int i=1;i<=n;++i) a[i]=read();
	for(int i=n;i;--i) {
		++p[a[i]];
		if(p[a[i]]>1) { ans=i; break; }
	}
	printf("%lld\n",ans);
}
signed main() {
	t=read();
	while(t--) solve();
}

C. Minimum Varied Number

注意到 \(t \in [1,45]\),说明答案最大就是 \(123456789\),那么要求数字最小只要贪心从后往前依次放置即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int t, n, ans[100];
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
void solve() {
	n=read();
	memset(ans,0,sizeof(ans));
	for(int i=9;i;--i) if(n>i) {
		n-=i; ans[i]=i;
	} else { ans[i]=n; break; }
	for(int i=1;i<=10;++i) if(ans[i]) printf("%lld",ans[i]);
	puts("");
}
signed main() {
	t=read();
	while(t--) solve();
}

D. Color with Occurrences

注意到颜色是可以覆盖的,所以也可以理解为“无后效性吧”。

那么设 \(f(i)\) 为将 \([1,i]\) 染色用的最小次数,那么对于一个字符串 \(j\) \[ f(i) = \min_{k \in [i-l_j,i-1]}{ \{ f_k + 1} \} \] 其中 \(l_j\)\(j\) 的长度,且必须满足 \(i \ge l_j\)\(t[i-l_j+1,i] = a_j\)

为啥不把 \(j\) 加入状态呢?复杂度是不会变化的,是冗余信息。

考虑输出方案。一开始我竟然用了一个 SB 二维数组乱搞,结果还真的过了样例和第一个点,但是会 WA #2。仔细一想,输出方案实际上是把 DP 的过程重现一遍,那么输出方案时需要的信息应当与状态相同,但是由于不仅要输出决策点,还要输出所用的字符串编号,所以要用两个数组。我一开始就是把这两个合一了

\(g_1(i)\) 表示决策点,\(g_2(i)\) 表示将 \(i\) 染色用的字符串编号。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=105, M=15;
int t, n, m, f[N], l[M], g1[N], g2[N];
string s, a[M];
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
void print(int i) {
    // i表示染色的位置
	if(!i) return;
	print(g1[i]);
    // i的决策点,也就是上一个染色的位置
	printf("%lld %lld\n",g2[i],i-l[g2[i]]+1);
    // 用的字符串编号的染色的位置
}
void solve() {
	memset(f,0x3f,sizeof(f));
	memset(l,0,sizeof(l));
	memset(g1,0,sizeof(g1));
	memset(g2,0,sizeof(g2));
	cin>>s; n=read();
	m=s.length(), s=" "+s;
	for(int i=1;i<=n;++i) cin>>a[i], l[i]=a[i].length();
	f[0]=0;
	for(int i=1;i<=m;++i) for(int j=1;j<=n;++j) if(i>=l[j]) {
		if(s.substr(i-l[j]+1,l[j])==a[j]) {
			int p=m+1;
			for(int k=i-l[j];k<i;++k) if(f[p]>f[k]) p=k;
			if(f[i]>f[p]+1) f[i]=f[p]+1, g1[i]=p, g2[i]=j;
		}
	}
	printf("%lld\n",f[m]<=m? f[m]:-1);
    // 不难发现只要能够全部染色,次数绝不会超过m
	if(f[m]<=m) print(m);
}
signed main() {
	t=read();
	while(t--) solve();
}

E. Add Modulo 10

注意到如果某个数模 \(10\)\(0\),那么它就不会变化,如果模 \(10\)\(5\),那么它只会改变一次。

它们可以归为一类——因为它们的终态都能计算出来,姑且称之为 \(\alpha\) 类,其他称之为 \(\beta\) 类。如果既有 \(\alpha\) 类又有 \(\beta\) 类,那么绝对不可能全部相等。

否则如果只有 \(\alpha\) 类,那么直接算出来判断是否全部相等即可。

未经特殊声明,下面的数都是模 \(10\) 之后的结果。

考虑这样一条路径,\(1 \rightarrow 2 \rightarrow 4 \rightarrow 8\)

\(3 \rightarrow 6 \rightarrow 2\)\(7 \rightarrow 4\)\(9 \rightarrow 8\),这些操作都能让本不属于这条路径的数字加入路径,且最终都会达到 \(8\),那么可以知道一定能做到让所有的数模 \(10\) 相同,但是一定能全部相等吗?

注意到 \(8\)\(28\),将 \(8\) 进行变成 \(28\) 需要 \(4\) 次操作,但是根本无法让 \(28\) 变成 \(38\)。这是因为路径中 \(8\) 变成 \(8\) 要进位两次,所以只有个位是 \(8\) 的两个数的差是 \(10\) 的偶数倍才能满足条件。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int t, n, a[N], f1, f2;
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
bool pd(int a,int b) {
	int d=abs(a-b);
	return (d/10)%2;
}
void solve() {
	n=read();
	f1=f2=0;
	for(int i=1;i<=n;++i) {
		a[i]=read();
		if(a[i]%10==0||a[i]%10==5) f1=1;
		else f2=1; 
	}
	if(f1&&f2) { puts("No"); return; }
	else if(f1) {
		for(int i=1;i<=n;++i) {
			if(a[i]%10==5) a[i]+=5;
			if(i>1&&a[i]!=a[i-1]) { puts("No"); return; }
		}
		puts("Yes"); return;
	} else {
		for(int i=1;i<=n;++i) {
			if(a[i]%10==1||a[i]%10==2||a[i]%10==4) {
				a[i]-=a[i]%10, a[i]+=8;
			}
			else if(a[i]%10==3||a[i]%10==6||a[i]%10==7||a[i]%10==9) {
				a[i]-=a[i]%10, a[i]+=18;
			}
			if(i>1&&pd(a[i],a[i-1])) { puts("No"); return; }
		}
		puts("Yes"); return;
	}
}
signed main() {
	t=read();
	while(t--) solve();
}

F. Build a Tree and That Is It

没看,不会。😢

G. Path Prefixes

维护树上前缀和,记为 \(sa\)\(sb\)

在一条路径上,找到第一个严格大于 \(sa_x\)\(sb_y\),那么 \(sa_x\) 一定严格大于之前的每一个 \(sb\),于是 \(y-1\) 即为答案。\(x\)\(y\) 都是路径上节点的编号。由于 \(sb\) 显然是单调增的,可以二分查找。

在更新更新完 \(x\) 的所有子节点之后还原 \(sa_x\)\(sb_x\) 即可。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+5;
int t, n,  sa, sb, a[N], b[N], ans[N];
int tot, h[N], to[2*N], nxt[2*N];
vector<int> ssb;
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
void add(int x,int y) {
	to[++tot]=y, nxt[tot]=h[x], h[x]=tot;
}
void dfs(int x,int fa) {
	sa+=a[x], sb+=b[x];
	ssb.push_back(sb);
	ans[x]=upper_bound(ssb.begin(),ssb.end(),sa)-ssb.begin()-1;
	for(int i=h[x];i;i=nxt[i]) {
		int y=to[i];
		if(y!=fa) dfs(y,x);
	}
	sa-=a[x], sb-=b[x];
	ssb.pop_back();
}
void solve() {
	n=read();
	tot=sa=sb=0;
	ssb.clear();
	for(int i=1;i<=n;++i) h[i]=0;
	for(int i=2;i<=n;++i) {
		int p=read();
		a[i]=read(), b[i]=read();
		add(p,i), add(i,p);
	}
	dfs(1,0);
	for(int i=2;i<=n;++i) printf("%lld%c",ans[i]," \n"[i==n]);
}
signed main() {
	t=read();
	while(t--) solve();
}

「Codeforces Round」#811 (Div 3)
https://yozora0908.github.io/2022/cf1714-solution/
作者
yozora0908
发布于
2022年8月4日
许可协议