zoukankan      html  css  js  c++  java
  • XXII Open Cup. Grand Prix of Korea

    H.Or Machine

    4s

    Problem

    给定 (n) 个不超过 (2^8) 的数字 (x_1~x_n)
    给定 (l) 个操作 ((a,b)),表示 (x_a = x_a | x_b),其中 (|) 是按位或。
    给定 (t) 表示进行 (t) 次操作,按照操作(0),操作(1),……,操作(l-1),操作(0),操作(1),……,操作(l-1),操作(0),操作(1),……,操作(l-1),……的顺序。
    求最后得到的 (x_1~x_n) 的值
    (1leq n,lleq 2^{18} , 1leq tleq 10^{18})

    Solution

    显然可以把8位分开做。
    即只需考虑 (x_i in {0,1}) 的情况
    可以发现 当 (x_i) 变成 (1) 后,就不可能变回 (0) ,于是只需求出每个数变成 (1) 的时间,和 (t) 做比较即可。
    对于每个操作 从(b)(a)连边,边权为操作的下标。然后直接 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) 的个数。
    注意:周期不一定都是最小正周期。
    (1leq nleq 50,|x_i|leq 10^9,a_ileq 100)

    Solution

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

    两个 (n*n) 的矩阵 (A,E)。满足:(E_{i,j}=sum_{x=1}^nsum_{y=1}^n dis(i,j,x,y)*A_{x,y}),where (dis(i,j,x,y)=|i-x|+|j-y|)
    给出 (n,E) ,求 (A)

    Solution

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

  • 相关阅读:
    Java开发环境搭建(一)
    Android随笔之——Android广播机制Broadcast详解
    Ubuntu 14.04 LTS中怎样安装fcitx中文输入法
    Jenkins:容器化微服务持续集成-高配版
    Jenkins:容器化微服务持续集成-低配版
    JVM(1):JVM与Java体系结构
    RocketMQ:集群搭建
    RocketMQ:单机搭建
    Spring Cloud OAuth2:分布式认证授权
    Spring Security OAuth2:SSO单点登录
  • 原文地址:https://www.cnblogs.com/int-2147483648/p/15488200.html
Copyright © 2011-2022 走看看