XXII Open Cup. Grand Prix of Korea

H.Or Machine

4s

Problem

给定 n 个不超过 28 的数字 x1 xn
给定 l 个操作 (a,b),表示 xa=xa|xb,其中 | 是按位或。
给定 t 表示进行 t 次操作,按照操作0,操作1,……,操作l1,操作0,操作1,……,操作l1,操作0,操作1,……,操作l1,……的顺序。
求最后得到的 x1 xn 的值
1n,l218,1t1018

Solution

显然可以把8位分开做。
即只需考虑 xi{0,1} 的情况
可以发现 当 xi 变成 1 后,就不可能变回 0 ,于是只需求出每个数变成 1 的时间,和 t 做比较即可。
对于每个操作 从ba连边,边权为操作的下标。然后直接 Dijkstra 即可,当然 路径长度不是简单的边权之和,具体见代码。

Code

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
template<typename T> inline void read(T &x){
	x=0; bool f=false; char c=getchar();
	while(!isdigit(c)){ if(c=='-') f=true; c=getchar(); }
	while(isdigit(c)){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); }
	if(f) x=-x;
}
template<typename T> void print(T x){
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
const int N=1000006;
int n,l,t,x[N],y[N],dis[N],ans[N];
int to[N],w[N],nxt[N],head[N],cnt;
inline void add(int a,int b,int c){to[++cnt]=b;w[cnt]=c;nxt[cnt]=head[a];head[a]=cnt;return;}
int merg(int a,int b){
	if(a==0) return b+1;
	if((a-1)%l<b) return a+b-(a-1)%l;
	return a+b-(a-1)%l+l;
}
bool vis[N];
priority_queue<pair<int,int> > q; 
void dijkstra(){
	memset(vis,0,sizeof(vis)); 
	for(int i=1;i<=n;++i) if(dis[i]==0) q.push(make_pair(0,i));
	while(!q.empty()){
		int now=q.top().second;q.pop();
		if(vis[now]) continue; vis[now]=true;
		for(int i=head[now];i;i=nxt[i]){
			if(dis[to[i]] > merg(dis[now],w[i])){
				dis[to[i]] = merg(dis[now],w[i]);
				q.push(make_pair(-dis[to[i]],to[i]));
			}
		}
	}
	return;
}

signed main(){
	read(n);read(l);read(t);
	for(int i=0,a,b;i<l;++i) {
		read(a);read(b);
		add(b,a,i);
	}
	for(int i=1;i<=n;++i) read(x[i]);
	for(int k=1;k<256;k*=2){
		for(int i=1;i<=n;++i) dis[i]=1000000023330000018ll;
		for(int i=1;i<=n;++i) {
			y[i]=(x[i]&k);
			if(y[i]) dis[i]=0;
		}
		dijkstra();
		for(int i=1;i<=n;++i) if(dis[i]<=t) ans[i]+=k;
//		for(int i=1;i<=n;++i) cout<<dis[i]<<' '; cout<<endl;
	}
	for(int i=1;i<=n;++i) printf("%lld ",ans[i]);
	return 0;
}

J.Periodic Ruler

2s

Problem

有一把无限长的尺子,被染上了颜色,颜色用1~100的整数表示。
尺子的颜色序列有一个最小正周期。
现在已知尺子上 n 个点的颜色,求出所有的 t 满足:无论其余点如何染色, t 都不是尺子的最小正周期。
输出这些 t 之和,以及 t 的个数。
注意:周期不一定都是最小正周期。
1n50,|xi|109,ai100

Solution

注意到n只有50,但有100种颜色。
对于任意一个 t,我们可以得到一个长为t的数组,把每个点的颜色按他们的坐标模t的余数对应过来。
考虑比 n 大的 t
对于任意两个颜色不同的位置,他们的距离的因数一定满足条件。
除此之外 一定不满足条件。这是因为 t 一定是尺子的周期,且得到的 t 数组一定没有被完全染色,而我们手中又有50多个没用过的颜色,所以(我猜测)一定可以构造出一种方案使得 t 是最小正周期。
考虑不超过 nt
枚举这些 t
假如按照模t对应过来的颜色有冲突,则满足条件。
若没有冲突,假如有未染色格子,则不满足条件(同比n大的情况)。
若没有冲突且完全染色,则O(t)枚举所有比t小的数,检查是不是周期。若都不是则不满足条件,若有一个是则满足条件。

Code

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
template<typename T> inline void read(T &x){
	x=0; bool f=false; char c=getchar();
	while(!isdigit(c)){ if(c=='-') f=true; c=getchar(); }
	while(isdigit(c)){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); }
	if(f) x=-x;
}
template<typename T> void print(T x){
	if(x>9) print(x/10);
	putchar(x%10+'0');
}
int n,x[100],a[100],cnt,sum;
map < int , bool > ans;
void solve1(int dis){
	//dis 大于 n 的 因子 
	for(int i=1;i*i<=dis;++i){
		if(dis%i==0){
			if(i>n) ans[i]=true;
			if(dis/i>n) ans[dis/i]=true;
		}
	}
	return;
}
int T[100];
bool solve2(int t){
	//若有冲突 入队 
	//else	若未填满  不入
	// 		若填满 O(t^2)找有没有更小的 --> 有则入队  
	memset(T,0,sizeof(T));
	for(int i=1;i<=n;++i){
		if(T[x[i]%t] && T[x[i]%t]!=a[i]) return 1;
		T[x[i]%t]=a[i];
	}
	for(int i=0;i<t;++i) if(T[i]==0) return 0;
	for(int tt=1;tt<t;++tt){
		for(int i=0;i<t;++i)
			if(T[i]!=T[(i+tt)%t])
				goto nxt;
		return 1;
		nxt:;
	}
	return 0;
}
signed main(){
	read(n);
	for(int i=1;i<=n;++i) read(x[i]),read(a[i]),x[i]+=1000000010;
	for(int i=1;i<=n;++i)
		for(int j=i+1;j<=n;++j)
			if(a[i]!=a[j]){
				solve1(abs(x[i]-x[j]));
			}
	for(int t=1;t<=n;++t){
		if(solve2(t)) ans[t]=true;
	} 
	for(auto it : ans) if(it.second) ++cnt,sum+=it.first/*,print(it.first)*/;
	printf("%lld %lld",cnt,sum);
	return 0;
}

A.Automatic Sprayer 2

2s

Problem

两个 nn 的矩阵 A,E。满足:Ei,j=x=1ny=1ndis(i,j,x,y)Ax,y,where dis(i,j,x,y)=|ix|+|jy|
给出 n,E ,求 A

Solution

E的任意一行二阶差分得到矩阵A2 n1列每列的和sum1[2 n1]
E的任意一列二阶差分得到矩阵A2 n1行每行的和sum2[2 n1]
对于E的四个角,以左上角为例。
E1,1=i=1n(i1)sum1[i]+i=1n(i1)sum2[i]=(n1)(sum1[n]+sum2[n])+i=1n1(i1)sum1[i]+i=1n1(i1)sum2[i]
于是可以求出sum1[n]+sum2[n]。同理得到sum1[1]+sum2[1],sum1[1]+sum2[n]。再结合 i=1nsum1[i]=i=1nsum2[i]。即可解出 sum1[1],sum1[n],sum2[1],sum2[n]
这样就得到了所有的 sum1[1 n],sum2[1 n]
下面只要构造任何一个满足上述条件的 A 即可。
构造方法:枚举每个格子(i,j)Ai,j=min(sum1[j],sum2[i])sum1[j]=Ai,j,sum2[i]=Ai,j

作者:_Veritas
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。

posted @   _Veritas  阅读(482)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· Vue3状态管理终极指南:Pinia保姆级教程
点击右上角即可分享
微信分享提示