zoukankan      html  css  js  c++  java
  • 洛谷比赛 「EZEC」 Round 4

    洛谷比赛 「EZEC」 Round 4

    T1 zrmpaul Loves Array

    题目描述

    小 Z 有一个下标从 (1) 开始并且长度为 (n) 的序列,初始时下标为 (i) 位置的数字为 (i)。有 (m) 个操作,每个操作会是以下四种之一。

    • 1 对序列从小到大进行排序。
    • 2 对序列从小到大进行排序后将其翻转,(译者注:就是从大到小排序)。
    • 3 x y 将下标为 (x,y) 的数交换位置。保证 (x eq y)(1le x,yle n)
    • 4 将序列翻转。

    你要输出在 (m) 次操作后的序列。

    输入格式

    第一行两个整数 (n,m) ,表示序列的长度以及操作的数量。

    接下来 (m) 行,每行一个操作。保证操作合法。

    输出格式

    一行包含 (n) 个整数,表示操作后的序列。

    输入输出样例

    输入 #1

    5 5
    1
    2
    3 2 4
    4
    3 1 5
    

    输出 #1

    5 4 3 2 1
    
    说明/提示

    【数据范围】

    【本题采用捆绑测试】

    subtask 1(24pts): (1leq n,mleq 2 imes 10^3)

    subtask 2(13pts): 没有操作三。

    subtask 3(63pts): (1leq n,mleq 10^6)

    【样例解释】

    序列经过的操作为:

     1,2,3,4,5
     1,2,3,4,5
     5,4,3,2,1
     5,2,3,4,1
     1,4,3,2,5
     5,4,3,2,1
    

    签到题还是有点思维难度的,但也比至于那么难,不过需要注意的点比较多。

    自己在一个点上卡了一个小时(太菜了,该退役了)。

    现讲一下思路吧。观察一下这四个操作,你就会发现一个神奇的规律。

    在排序操作之前的操作是对答案没有任何影响的。

    所以,我们只需要找到最后的一个操作(1) 或者操作 (2) ,如果最后一次是操作 (1) 原序列就正着排,反之倒着排序。

    之后,我们就可以模拟操作三和操作四了。

    操作三直接暴力 (swap) ,操作四的话可以打个标记,奇数的把这个序列暴力翻转。

    一个比较坑的点就是一开始要把原序列赋为从 (1-n) 的排列,(因为他可能只有操作 (4))

    随机数据的话还是跑的比较快的。

    具体实现看代码把:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,type,maxn,res,cnt,a[1000010];
    struct node
    {
    	int opt,x,y;
    }q[1000010];
    inline int read()
    {
        int s = 0,w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
        return s * w;
    }
    int main()
    {
    	n = read(); m = read();
    	for(int i = 1; i <= n; i++) a[i] = i;//一开始序列为1-n 的排列
    	for(int i = 1; i <= m; i++)
    	{
    		q[i].opt = read();
    		if(q[i].opt == 3)
    		{
    			cnt++;
    			q[i].x = read(); q[i].y = read();
    		}
    		if(q[i].opt == 1 || q[i].opt == 2)//找最后一次排序操作
    		{
    			type = q[i].opt; maxn = i;
    		}
    	}
    	if(type == 1)//如果是 1 就升序排列
    	{
    		for(int i = 1; i <= n; i++) a[i] = i;
    	}
    	if(type == 2)//反之降序排列
    	{
    		for(int i = n; i >= 1; i--) a[i] = n-i+1;
    	}
    	for(int i = maxn+1; i <= m; i++)
    	{
    		if(q[i].opt == 3)
    		{			
    		    if(res & 1)//如果前面序列反转了偶数次,就对序列暴力翻转
    			{
    				for(int j = 1; j <= n/2; j++) swap(a[j],a[n-j+1]);
    			}
    			swap(a[q[i].x],a[q[i].y]);//暴力交换
    			res = 0;
    		}
    		else if(q[i].opt == 4) res += 1;//统计有多少个操作 4
    	}
    	if(res & 1) for(int i = 1; i <= n/2; i++) swap(a[i],a[n-i+1]);
    	for(int i = 1; i <= n; i++) printf("%d ",a[i]);
    	return 0;
    }
    

    T2「EZEC-4」可乐

    题目背景

    很久以前,有一个 pigstd,非常迷恋美味的可乐。为了得到美味的可乐,他几乎用尽了所有的钱,他甚至对自己的 npy 也漠不关心其实是因为他没有npy,更不爱好看戏。除非买了新可乐,才会坐上马车出门炫耀一番。每一天,每个钟头他都要喝上一瓶新可乐。

    pigstd 最近又买了许多箱新可乐——当然,这些可乐只有聪明的人才能喝到。

    题目描述

    pigstd 现在有 (n) 箱可乐,第 (i) 箱可乐上标着一个正整数 (a_{i})

    若 pigstd 的聪明值为一个非负整数 (x),对于第 (i) 箱可乐,如果 ((a_{i} oplus x )le k) 那么 pigstd 就能喝到这箱可乐。

    现在 pigstd 告诉了你 (k) 与序列 (a),你可以决定 pigstd 的聪明值 (x),使得他能喝到的可乐的箱数最大。求出这个最大值。

    输入格式

    第一行两个由空格分隔开的整数 (n,k)

    接下来 (n) 行,每行一个整数 (a_i),表示第 (i) 箱可乐上标的数。

    输出格式
    一行一个正整数,表示 pigstd 最多能喝到的可乐的箱数。
    输入输出样例

    输入 #1

    3 5
    2
    3
    4
    

    输出 #1

    3
    

    输入 #2

    4 625
    879
    480
    671
    853
    

    输出 #2

    4
    
    说明/提示

    提示

    pigstd 的聪明值 (x) 可以为 (0)

    样例解释

    样例 1 解释:容易构造当 (x=0) 时,可以喝到所有可乐。

    样例 2 解释:容易构造 (x=913),可以喝到所有可乐。

    样例解释未必是唯一的方法。

    数据范围

    本题采用捆绑测试。

    • Subtask 1(29 points):(1 le n,k,a_{i} le 1000)
    • Subtask 2(1 point):(a_{i} le k)
    • Subtask 3(70 points):无特殊限制。

    对于所有数据,保证 (1 le n,k,a_{i} le 10^6)

    一开始看错题了,连交了几发全是 WA,差点把我心态搞崩了

    这道题我和 STd 的解法不太一样。

    这道题看到异或,我们会想到什么。 没错,就是 (01tire)

    我们可以对每个 (a_i) 都插入 (tire) 树中,然后暴力枚举 (x)

    找在异或起来不小于 (k) 的情况下,能喝到的可乐最多。

    主要是分情况讨论比较难写,但其他的还算可以。

    Code:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,k,tot = 1,siz[20000100],x,tr[20000100][2];
    int ans,kk,maxn;
    inline int read()
    {
        int s = 0,w = 1; char ch = getchar();
        while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9'){s =s * 10+ch - '0'; ch = getchar();}
        return s * w;
    }
    void insert(int x)//建 tire 树
    {
    	int p = 1;
    	for(int i = 20; ~i; i--)
    	{
    		int c = (x>>i)&1;
    		if(!tr[p][c]) tr[p][c] = ++tot;
    		p = tr[p][c];
            siz[p]++;
    	}
    }
    int query(int x)
    {
    	int p = 1, res = 0;
    	for(int i = 20; i; i--)
    	{
    		int a = (k>>i)&1, b = (x>>i)&1;
    		if(a == 0)//如果说 k的这一位为0,那么tire树上的节点只能和 b 相同
    		{
    			if(b == 1) p = tr[p][1];
    			if(b == 0) p = tr[p][0];
    		}
    		if(a == 1)
    		{
    			if(b == 0)
    			{
    				res += siz[tr[p][0]];//节点为 0 的话,异或起来小于 1可以直接记录答案
    				p = tr[p][1];
    			}
    			else
    			{
    				res += siz[tr[p][1]];//同理
    				p = tr[p][0];
    			}
    		}
    	}
    	int a =k & 1, b =x & 1;//最后一位的情况
    	if(a == 0)
    	{
    		if(b == 1) p = tr[p][1];
    		if(b == 0) p = tr[p][0];
    	}
    	if(a == 1)
    	{
    		if(b == 0)
    		{
    			res += siz[tr[p][0]];
    			p = tr[p][1];
    		}
    		else
    		{
    			res += siz[tr[p][1]];
    			p = tr[p][0];
    		}
    	}
    	return res;
    }
    int main()
    {
    	n = read(); k = read(); maxn = k;
    	for(int i = 1; i <= n; i++)
    	{
    		x = read();
    		maxn = max(maxn,x);//上限设为 a[i] 和 k 的最大值
    		insert(x);
    	}
    	for(int i = 0; i <= maxn<<1; i++)
        {
    		ans=max(ans,query(i));//暴力枚举 x
    	}
    	printf("%d
    ",ans);
    }
    

    后面的几道题就比较仙了。

    T3 Excalibur

    题目描述

    已知有 (n) 个血量均为 (k) 的敌人,编号(1sim n).

    给你一柄圣剑,选择一个敌人,砍向他并对其造成 (p) 点伤害。

    这柄圣剑还附有 (m) 条属性,第 (i) 条属性可表示为:

    • 1、若 (x_i) 号敌人受到了伤害,记此伤害为 (r_{x_i}) 那么 (y_i) 号敌人就会相应受到 (q imes r_{x_i})点伤害。
    • 2、若 (y_i) 号敌人受到了伤害,记此伤害为(r_{y_i}),那么 (x_i) 号敌人就会相应受到 (q imes r_{y_i}) 点伤害。
    • 3、上述两点若有任意一点被触发,该属性立即失效。

    现规定,当某个敌人血量 (le 0) 时,即视为你击杀了这个敌人。击杀与否不影响伤害大小。

    求你最多能击杀几个敌人。

    数据保证:

    1、每条属性中 (x_i eq y_i)

    2、所有属性本质上不重复。

    3 砍向任一敌人后,每个敌人最多受到一次伤害。

    输入格式

    第一行五个整数 (n,m,k,p),。

    (m) 行每行两个整数 (x,y)

    输出格式

    一行一个整数表示答案。

    输入输出样例

    输入 #1

    3 2 2 3 1
    1 2
    2 3
    

    输出 #1

    3
    

    输入 #2

    3 2 2 1 1
    1 2
    2 3
    

    输出 #2

    0
    

    输入 #3

    3 2 4 1 2
    1 2
    2 3
    

    输出 #3

    1
    
    说明/提示

    【样例 1 说明】

    砍向 1 号敌人,对其造成 3 点伤害;22号敌人随之受到 3 点伤害;3 号敌人随之受到 3 点伤害。共击杀 3 个敌人。

    【样例 2 说明】

    无法击杀任何敌人。

    【样例 3 说明】

    砍向 1 号敌人,对其造成 1 点伤害;2 号敌人随之受到 2 点伤害;3 号敌人随之受到 4 点伤害。共击杀 1个敌人。

    【数据规模与约定】

    对于 100% 的数据,(1le nle 10^5)(0le mle 10^5)(1le k,p,qle 10^9)(1le x,yle n)

    本题采用捆绑测试。

    子任务 分值 n q 特殊性质
    1 10 (≤10)
    2 5 =1
    3 5 对于每条属性都有 (xi=yi−1)
    4 20 保证数据随机生成
    5 60

    这道题我开始以为是道图论题。

    但,当我得知正解是树形 (dp) 时,我的表情是这样的:

    算了,贴正解吧:

    简化问题

    给你若干棵树,选一颗树上的一个点作为根,根节点深度为 1,问树上有多少节点深度 (h)

    [h leq egin{cases} log_q{k over p} + 1& ext{q > 1}\ infin & ext{q = 1, p <k}\ 1 & ext{q = 1, $ple k$} end{cases} ]

    观察数据范围,注意到 (q>1)(log_q(frac{k}{p})<30),故可以从这个切入点解决问题。

    考虑 ( ext{DP})

    (sz[i][j]) 为以节点 (i) 为根,深度等于 (j) 的节点数。

    (f[i][j]) 为以节点 (i) 为根,深度小于等于 (j) 的节点数。(最后求答案时用个容斥即可)

    易求得 (sz) 数组的递推式为 (sz[u][j]= displaystyle sum sz[v][j−1]),其中 (u)(v) 为父子关系,下同。

    当由父节点为根转为由子节点为根时,粗略观察到 (f[v][j])(f[u][j−1]) 很相似,进一步观察可得 (f[v][j]=f[u][j−1]+sz[v][j]+sz[v][j−1])

    在每棵树中任选一个节点为根,先求出这个节点的 (sz) 和 $ f$ 数组后,再换根 ( ext{DP}) 即可。

    别忘了特判 (q=1) 的情况哦!

    时间复杂度为 (O(nlog_q(frac{k}{p})))

    Code(正解代码):

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,m,k,p,q,x,y,l,max_,vis[100009],trsz[100009],sz[100009][39],f[100009][39];
    vector <ll> root,to[100009];
    inline ll read(){
       ll s = 0,w = 1;
       char ch = getchar();
       while (ch < '0'|| ch > '9'){ if (ch == '-') w = -1; ch = getchar();}
       while (ch >= '0'&& ch <= '9') s = (s << 1) + (s << 3) + (ch ^ 48),ch = getchar();
       return s * w;
    }
    void dfs1(ll u,ll fa,ll pos){
        trsz[pos] += 1,sz[u][1] = vis[u] = 1;
        for (ll i = 0;i < to[u].size();i += 1){
            ll v = to[u][i];
            if (v ^ fa){
                dfs1(v,u,pos);
                for (ll j = 2;j <= l;j += 1) sz[u][j] += sz[v][j - 1];
            }
        }
    }
    void dfs2(ll u,ll fa,ll pos){
        for (ll i = 0;i < to[u].size();i += 1){
            ll v = to[u][i];
            if (v ^ fa){
                f[v][1] = 1;
                for (ll j = 2;j <= l;j += 1) f[v][j] = f[u][j - 1] + sz[v][j] + sz[v][j - 1];
                max_ = max(max_,trsz[pos] - f[v][l]);
                dfs2(v,u,pos);
            }
        }
    }
    int main(){
        n = read(),m = read(),k = read(),p = read(),q = read();
        for (ll i = 0;i < m;i += 1) x = read(),y = read(),to[x].push_back(y),to[y].push_back(x);
        if (q == 1 && p < k){cout<<0; return 0;}
        while (p * pow(q,l) < k) l += 1;
        for (ll i = 1;i <= n;i += 1) if (!vis[i]) root.push_back(i),dfs1(i,0,i);
        for (ll i = 0;i < root.size();i += 1) for (ll j = 1;j <= l;j += 1)
            f[root[i]][j] = f[root[i]][j - 1] + sz[root[i]][j];
        for (ll i = 0;i < root.size();i += 1) max_ = max(max_,trsz[root[i]] - f[root[i]][l]);
        for (ll i = 0;i < root.size();i += 1) dfs2(root[i],0,root[i]);
        cout<<max_;
        return 0;
    }
    

    T4「EZEC-4」求和

    一句话题意:

    T组询问,每次询问输出

    (displaystylesum_{i=1}^{n}sum_{j=1}^{n} gcd(i,j)^{i+j} mod p) 的结果。

    看完题直接弃疗了,打了 (10pts) 就滚粗了

    直接甩个 (std) 的链接吧 link

    这么复杂的柿子谁推的出来啊。

    T5 「EZEC-4」月下轻花舞

    std

    一句话题意: (T) 组询问,每次给定三个整数 (l,r,n),求出下式的值:

    (displaystyle sum_{i=l}^{r} (i-1) imes sum_{j=1}^{n} ceil(log_i^{j}) mod 998244353)

    看到这个柿子,我直接大呼毒瘤。

    这考的时候,一点思路都没有。并且考到的还是一些自己没学过的东西(比如什么拉格朗日差值)。果然还是自己太菜了。

    T6 括号

    不会写,没看。

    好像正解是分块(毒瘤lxl逃

    总结

    这次打的还是很不错的,切了两道题。

    总分 100 + 100 + 0 + 10 + 0 + 0 = 210;

    混了个你谷 Rnk 17 。以后还要继续努力呀。

  • 相关阅读:
    在word中读取和写入中的表格
    随机生成简单验证码
    sql语句
    Jmeter 逻辑控制器 之 While Controller
    Jmeter 逻辑控制器 之 循环控制器
    Jmeter 逻辑控制器 之 事务控制器
    Jmeter 逻辑控制器 之 if 控制器
    android抓取logcat日志的方法
    使用Jmeter做性能测试
    测试案例累计分享
  • 原文地址:https://www.cnblogs.com/genshy/p/13623550.html
Copyright © 2011-2022 走看看