NOIp ( on line ) 提高组 2020 总结
T1 : 序列
题意:
一共有T组数据,每组数据有两个长度为n的序列a,b,m个操作,问a序列是否可以转换成b,是输出YES,否的话输出NO。
m个操作分别为ti,xi,yi,若t为1,则x和y上的数可同时加减一;若t为2,则x上的数加一同时y上的数减一,或y上的数加一同时x上的数减一;
大概理解为: 将a上的所有数变成b上的对应的数,当t=1时可以将a[x],a[y]同时加任何数,当t=2时可以将a[x]加任何数同时a[y]上的数减上相同的数(相当于把a[x]一部分值转到a[y]上);
列: a : 1 3 5 4 t=1,x=1,y=2 则若a[1] (1) 要加上3,a[2] (3) 也必须加上3,a 变成 4 6 5 4
t=2,x=1,y=2 则若a[1] (1) 要加上3,a[2] (3) 必须减去3,a变成 4 0 5 4;
数据范围:
1≤T≤10,1≤n,m≤105,1≤ai,bi≤109
分析:
这题可以用图论来做
先定义一个序列 c ,c[i]=a[i]-b[i],这样我们只要判断c中的每一个值是否可以变为零就行了。
然后读入m个操作
先不用管t为1时的情况,若 t 为2的话,把 x 和 y 之间连一条无向边,然后将图中的联通块缩点。
因为联通块中的任何俩个数都可以将他们的一部分值互相转换,所以可以将他们看做一个点,该点的权值就是联通块中的每一个c[i]的和。
下面记 i 点所在的联通块为bel[i]。
接下来再操作将t为1时的情况, 将bel[x]与bel[y]之间连一条无向边,若bel[x]=bel[y]则用一个bool数组表示bel[x]有自环,有自环后bel[x]的值就可以成2的倍数增长。
接下来就对新图进行缩点,可以发现,若两个点之间的路径长度为偶数时,两个点间可进行值的转移。
所以我们再将图进行黑白染色,同色点之间一定长度为偶数的路径,那么我们就将颜色相同的点进行缩点。
缩到最后,我们再将判断一下每个联通块是否可以将其的总权值变为零,如果有一个联通块不能将其总权值变为零,则输出NO,反之输出YES。
我们再看看如何判断联通块之间是否可以将其总权值变为零。
因为缩点缩到最后一定每个联通块最多只有两个点(黑点和白点),所以判断一下这两个点可不可以变为零就行了。
只要两个点的权值相同,那么就可以两个点同时加减变为零。
如果不相等,如果两个点其中一个有自环,且两个点权值差为偶数,那就可以将两个点的值变相同,之后再进行操作。
因为我们只需要判断联通块是否可以变成零就行了,所以不用建新图,dfs一下就行。
(我还是太弱了,考场上不会写图,只会n≤2的)
代码如下:
- #include<cstdio>
- #include<iostream>
- #include<algorithm>
- #include<cstring>
- #include<vector>
- using namespace std;
- typedef long long LL;
- const int N=;
- LL sum[N];
- int bel[N],a[N],color[N];
- bool book[N];
- vector<int> h[N],g[N];
- struct Node
- {
- int x,y;
- }w[N];
- void dfs1(int u,int c)//第一次缩点 (t为2时的边)
- {
- bel[u]=c;
- sum[c]+=a[u];
- for(int i=;i<g[u].size();i++)
- {
- int j=g[u][i];
- if(!bel[j])
- dfs1(j,c);
- }
- }
- bool dfs2(int u,int col,bool &pd,LL &suma,LL &sumb)//第二次缩点
- {
- if(~color[u]) return color[u]==col;//若颜色不一样说明有奇数环
- color[u]=col;//进行染色
- pd|=book[u];//判断有没有自环
- if(col==) suma+=sum[u];//将相同色的点权值相加
- else sumb+=sum[u];
- bool t=true;
- for(int i=;i<h[u].size();i++)
- {
- int j=h[u][i];
- t&=dfs2(j,col^,pd,suma,sumb);
- }
- return t;
- }
- int main()
- {
- int T;
- scanf("%d",&T);
- while(T--)
- {
- int n,m;
- int cnt_all=,cnt=;
- scanf("%d%d",&n,&m);
- for(int i=;i<=n;i++) scanf("%d",&a[i]);
- for(int i=;i<=n;i++)
- {
- int x;
- scanf("%d",&x);
- a[i]=x-a[i];
- g[i].clear();//将边初始化
- h[i].clear();
- }
- memset(w,,sizeof(w));
- while(m--)
- {
- int p,x,y;
- scanf("%d%d%d",&p,&x,&y);
- if(p==)
- {
- w[cnt_all++]={x,y};//存储当t为1时的边
- }
- else
- {
- g[x].push_back(y),g[y].push_back(x);//t为2时将x与y之间连边
- }
- }
- memset(sum,,sizeof(sum));//联通块总权值初始化
- memset(bel,,sizeof(bel));//每个点属于的联通块
- for(int i=;i<=n;i++)
- {
- if(!bel[i]) dfs1(i,++cnt);
- }
- memset(book,,sizeof(book));
- for(int i=;i<cnt_all;i++)
- {
- int x=bel[w[i].x],y=bel[w[i].y];
- if(x==y) book[x]=true;//判断自环
- else
- {
- h[x].push_back(y);//不是自环则加边
- h[y].push_back(x);
- }
- }
- bool ans=;
- memset(color,-,sizeof(color));//初始化颜色
- for(int i=;i<=cnt;i++)
- {
- if(color[i]==-)//若没被染过色
- {
- bool pd=false;//判断自环
- LL suma=,sumb=;//黑色和白色点的权值总和
- if(dfs2(i,,pd,suma,sumb))
- {
- if(pd) ans&=(suma+sumb)%==;//判断联通块权值是否可以变为零
- else ans&=suma==sumb;
- }
- else
- {
- ans&=(suma+sumb)%==;
- }
- }
- }
- if(ans) puts("YES");
- else puts("NO");
- }
- }
T2 :
不会 ~
T3 : 最小环
题意:
给定一个长度为 n 的正整数序列 ai,下标从 1 开始编号。
我们将该序列视为一个首尾相邻的环。
更具体地,对于 下标为 i, j(i⩽j) 的两个数 ai, aj,它们的距离为 min(j−i,i+n−j)。
现在再给定 m 个整数 k1, k2,..., km。
对每个 ki(i=1, 2,..., m),你需要将上面的序列 ai 重新排列,使得环上任意两个距离为 ki 的数字的乘积之和最大。
大概理解为:给一串数,让你将这串数重新排列,使任意两个中间间隔k-1个数的数的乘积之和最大(数列是头尾相连的)。
分析:
根据样例数据推断出,将最大的数两旁放次大的及第二大的,再将次大的数旁放第三大的,以此类推,最后的结果一定是最大的情况。
总的来说,每次将未放到环中最大的数放入到环中最大的数旁,可使环的结果最大。
我们只需要将最大的几个数放入一个环中,再将环中最大的几个数放在一起,总结果就最大了。
接下来,我们就将当k为0~n/2的情况预处理一下,最后询问时直接输出答案就行。
然后得算一下距离k与分成多少个环的关系。假设一个环中有些个数,那么 (x*k) mod n=0,所以x=gcd(n,k)。
(我没想到环的个数是用最大公约数求,只搞了k为一的)
代码如下:
- #include<cstdio>
- #include<iostream>
- #include<algorithm>
- #include<cstring>
- using namespace std;
- const int N=;
- long long a[N],f[N];
- bool com(int a,int b)
- {
- return a>b;
- }
- int gcd(int a,int b)//求最大公约数
- {
- return b ? gcd(b,a%b) : a;
- }
- int main()
- {
- int n,m;
- scanf("%d%d",&n,&m);
- for(int i=;i<=n;i++) scanf("%d",&a[i]);
- sort(a+,a+n+,com);//将数从大到小排序 找最大值好用
- for(int i=;i<=n;i++)//处理k为零的情况
- {
- f[]+=a[i]*a[i];
- }
- for(int k=;k<=n/;k++)
- {
- int t=gcd(n,k),num=n/t;//t为能分成多少个环 num为一个环有多少个数
- if(f[t]) continue;
- for(int i=;i<=n;i++)//依次枚举最大数放入环中
- {
- if(i%num==)//如果这是上一个环的最后一个数 就加上下一个环
- {
- f[t]+=a[i+]*a[i+];
- continue;
- }
- if((i+)%num==)//如果这是环的倒数第二个数
- {
- f[t]+=a[i]*a[i+];
- }
- else f[t]+=a[i]*a[i+];//正常情况下
- }
- }
- while(m--)
- {
- int k;
- scanf("%d",&k);
- if(!k) printf("%lld\n",f[]);//特判当k为零的情况
- else
- {
- k=gcd(n,k);
- printf("%lld\n",f[k]);
- }
- }
- }
NOIp ( on line ) 提高组 2020 总结的更多相关文章
- Codevs 1069 关押罪犯 2010年NOIP全国联赛提高组
1069 关押罪犯 2010年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description S 城现有两座监狱,一共 ...
- Codevs 1218 疫情控制 2012年NOIP全国联赛提高组
1218 疫情控制 2012年NOIP全国联赛提高组 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description H 国有 n 个城市,这 ...
- Codevs 3289 花匠 2013年NOIP全国联赛提高组
3289 花匠 2013年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 花匠栋栋种了一排花,每株花都 ...
- Codevs 1173 最优贸易 2009年NOIP全国联赛提高组
1173 最优贸易 2009年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description [问题描述] C 国有n ...
- Codevs 3731 寻找道路 2014年 NOIP全国联赛提高组
3731 寻找道路 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 在有向图G中,每条边的长度均为1,现给定起点和终点,请你在图中找 ...
- Codevs 1138 聪明的质监员 2011年NOIP全国联赛提高组
1138 聪明的质监员 2011年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 小 T 是一名质量监督员, ...
- Codevs 1217 借教室 2012年NOIP全国联赛提高组
1217 借教室 2012年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 在大学期间,经常需要租借教 ...
- Codevs 1064 虫食算 2004年NOIP全国联赛提高组
1064 虫食算 2004年NOIP全国联赛提高组 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 所谓虫食算,就是原先的算式 ...
- Codevs 1198 国王游戏 2012年NOIP全国联赛提高组
1198 国王游戏 2012年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description 恰逢 H 国国庆,国王邀 ...
随机推荐
- Java实现 蓝桥杯VIP 算法提高 前10名
算法提高 前10名 时间限制:1.0s 内存限制:256.0MB 问题描述 数据很多,但我们经常只取前几名,比如奥运只取前3名.现在我们有n个数据,请按从大到小的顺序,输出前10个名数据. 输入格式 ...
- Java实现 泊松分酒
泊松是法国数学家.物理学家和力学家.他一生致力科学事业,成果颇多.有许多著名的公式定理以他的名字命名,比如概率论中著名的泊松分布. 有一次闲暇时,他提出过一个有趣的问题,后称为:"泊松分酒& ...
- 如何0基础学习C/C++?
谈及C/C++,功能强大.应用广泛,一旦掌握了后,若是再自学其他语言就显得轻而易举了.那为什么学C/C++的人少呢?很多人认为C/C++虽然博大精深,但也难学.其实就本人认为C/C++并非是“diff ...
- MySQL进阶篇(02):索引体系划分,B-Tree结构说明
本文源码:GitHub·点这里 || GitEE·点这里 一.索引简介 1.基本概念 首先要明确索引是什么:索引是一种数据结构,数据结构是计算机存储.组织数据的方式,是指相互之间存在一种或多种特定关系 ...
- js数组的常见操作( push、pop、unshift、shift、splice、concat、 join)的用法
1.数组添加删除 头部或尾部( push().pop().unshift().shift() ) 例2.数组尾部添加 push()方法可向数组的末尾添加一个或多个元素,并返回新的长度 语法:array ...
- centos7 和centos6 服务操作命令对比
以httpd为例子: 指令名称 centos 6 centos 7 启动服务 service httpd start systemctl start httpd.service 关闭服务 servic ...
- FTP 常用命令
1. 准备 1.1 ftp 信息: ftp 服务器地址:192.168.168.10 用户名:will 密码:123 1.2 ftp 工具 使用 Windows 命令行: “开始” 按钮-> 搜 ...
- 图解KMP以及next数组的求法
在计算机科学中,Knuth-Morris-Pratt字符串查找算法(简称为KMP算法)可在一个主文本字符串S内查找一个模式串P的出现位置.此算法通过运用对这个模式串在不匹配时本身就包含足够的信息来确定 ...
- [计网笔记] 传输层---TCP 传输层思维导图
传输层思维导图 TCP笔记 为什么是三次握手和四次挥手 https://blog.csdn.net/baixiaoshi/article/details/67712853 [问题1]为什么连接的时候是 ...
- BUAA_OO_2020_Unit3_总结博客
BUAA_OO_2020_Unit3_总结 2020年春季学期第十三周,OO第三单元落下帷幕,对这个单元的内容JML有了更深的理解,但也有了一些疑惑,下做总结: 一.JML语言以及工具链 经过课上JM ...