51 nod系列
4级算法
数学
最大的最大公约数
题目来源: SGU
基准时间限制:1 秒 空间限制:65536 KB 分值: 40
给出N个正整数,找出N个数两两之间最大公约数的最大值。例如:N = 4,4个数为:9 15 25 16,两两之间最大公约数的最大值是15同25的最大公约数5。
Input
第1行:一个数N,表示输入正整数的数量。(2 <= N <= 50000)
第2 - N + 1行:每行1个数,对应输入的正整数.(1 <= S[i] <= 1000000)
Output
输出两两之间最大公约数的最大值。
Input 示例
4
9
15
25
16
Output 示例
5
题目价值 :
正难则反 : 数字很大不能直接计算gcd比较大小而要枚举因数,就没那么多了,如果一个因数两个数都有则是两数的工约数。
从大到小枚举:一旦出现两次就退出。学会思考题目的特性
暑假那几天自己打:
Atcode系列
D - Equal Cut
题意:将长为n的序列分成连续的4个非空区间,求出每个区间的和,使得max(区间和)-min(区间和) 最小。
思路
切三刀要枚举三个切口,这样n^3一定挂了,很舒服。
所以 考虑 确定一个最中间的位置,然后根据最优性来得到l和r的最优位置。
定一移他 ##:考虑确定一个元素,再根据提设来计算其他的最优。
define: 区间从左到右为A,B,C,D;
为了让小的尽量大,大的尽量小,所以要让A与B差值尽量小,C与D也同理,然后算出四个区间值,从小到大排序。ans与最大-最小比较。
code
#include<bits/stdc++.h>
#define N 200005
#define maxint 1000000001
#define LL long long
using namespace std;
LL a[N],sum[N];
int n;
int main(){
scanf ("%d",&n);
for (int i = 1;i <= n;i++)
{
scanf("%lld",&a[i]);
sum[i] = sum[i-1] + a[i];
}
LL ans = sum[n];
for (int i = 1,l = 1,r = 2;i < n - 1; i++)
{
//abs那里化简了 (sum[i]-sum[l]) - sum[l];and sum[n]-sum[r]-(sum[r] - sum[i])
while(l < i && abs(sum[i] - 2*sum[l]) > abs(sum[i] - 2*sum[l+1])) l++;
while(r < n && abs(sum[n] + sum[i] - 2 * sum[r]) > abs(sum[n] + sum[i] - 2*sum[r+1])) r++;
//cout<<l<<" "<<i<<" "<<r<<endl;
LL pass[5];
pass[1] = sum[n] - sum[r];
pass[2] = sum[r] - sum[i];
pass[3] = sum[i] - sum[l];
pass[4] = sum[l];
sort(pass+1,pass+5);
if(ans > pass[4] - pass[1]){
ans = pass[4] - pass[1];
//cout<<pass[4]<<" "<<pass[1]<<endl;
}
}
cout<<ans<<endl;
}
C - Minimization
大意:长为n的排列,每次可以把k个数全部变成这k个数之间的最小指。最少要多少次操作。
分析:
在考试的时候发现与其他数字无关,只与最小值有关,弄了好久才过。
其实也发现了跟所有的数字都无关。
所以要仔细分析题目的特性。
UVA系列
- UVA11020 优势人群
- 题义:比如有两个帅哥A和B,公主给他们打的分数是LA、CA(Lineage血统,Charm魅力)和LB、CB,B要是比A有优势,只要满足以下条件之一即可:
LB < LA 且 CB <= CA
LB <= LA 且 CB < CA
换句话说,只有当B的某个分数比A低,且另一个分数也不比A高时,B才是比A有优势的人。
公主会看中那些有优势(efficient或Pareto-optimal帕累托最优)的帅哥,当然,这个“有优势帅哥列表”5分钟更新一次。
给出每个帅哥的得分,计算在当前已有信息的前提下,有多少人是有优势的。
输入格式
每组测试数据的第一行是n(0≤n≤15000),表示应召新郎的人数
以下有n行,每一行是公主的两个打分分值,分值范围[0, 109]
输出格式
对于每组测试数据,输出获得每条信息后,有优势的人数。每组测试数据间空一行,格式参考样例
分析:
人数只增不减,一旦失去优势,在也不会得到优势。所以可以将其删除。
把两个标准变成坐标x,y。x大则y小,所以是单调递减的。
考虑到目前为止所有人都是有优势的。新加入的点有两种情况:
一.没有优势,即x大于最近左边的点而y大于他。可以直接删除。
二.有优势,即与上面相反。要比较其他点是否失去优势将其删除。
因为mulset已经按x从大到小排好序了,所以只要比较y就可以了
借鉴之处:
>
结构体比较函数。
lower_bound(p)第一个>=p的位置,upper_bound(p)第一个>p的位置
mulset,可重集。
struct node{
int x,y;
bool const operator < (const &node rp) const {
return x < rp.x || ( x == rp.x && y < rp.y);
}//从小到大排。反之改下符号。!!
};
UVA11464 Even Parity
-题义
给你一个n*n的01矩阵(每个元素非0即1),你的任务是把尽量少的0变成1,使得上、下、左、右的元素(如果存在的话)之和均为偶数。
-分析:
之前的选择会影响后面的决策。找到最初的决策
第一层的选择能推出后面的层数:
#include<bits/stdc++.h>
using namespace std;
int a[20][20],b[20][20],ans = 9999,n;
int jc(int x,int y){
int sum = 0;
if(y+1 <= n) sum += b[x][y+1];
if(x-1 >= 1) sum += b[x-1][y];
if(y-1 >= 1) sum += b[x][y-1];
return sum;
}
void work()
{
for(int i = 1;i < n;i++)
for(int j = 1;j <= n;j++)
b[i+1][j] = jc(i,j)&1;
int cent = 0;
for(int i = 1;i <= n ;i++)
for(int j = 1;j <= n ;j++)
if(a[i][j] == 1 && b[i][j] == 0)return ;
else cent += (a[i][j] != b[i][j]);
ans = min(ans,cent);
}
void dfs(int cent){
if(cent == n + 1)
{
work();return ;}
else{
b[1][cent] = 1;
dfs(cent + 1);
b[1][cent] = 0;
dfs(cent + 1);
}
}
int main(){
int T;
scanf("%d",&T);
for (int kase = 1;kase <= T ;kase ++){
scanf("%d",&n);
for (int i = 1;i <= n ;i++)
for (int j =1; j <= n ;j++)scanf("%d",&a[i][j]);
ans = 9999;
dfs(1);
if(ans == 9999)printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}
//此代码A不了,格式问题。
//A
UVA 12124 Assemble
题意:你有b块钱,给出n个配件各自的种类,品质因子和价格,要求每种类型的都要买一个,总价格不超过b,且品质最差配件的品质因子要尽量大
题目价值
如何二分,二分什么?
一般二分题目所求的答案,找到如果答案不满足会出现什么矛盾情况。分析: 这里的矛盾是:如果最差品质的不是p,那么不能在指定价格范围内拼成一台电脑。
code不是重点
。。。。
中间出现的错误
- vector下标是从0开始的。
- 忘记vector的初始化
- 忘记记录是否出现过某种类型。
- 如何把商品分类?
- map记录某种出现过< string,int >
- vector 是结构体型< node >
- price qulity 记在结构体里。
UVA1267
题义:一开始只有一个结点上有一个服务器, 为了让所有叶子结点距离服务器的距离不超过k, 我们在非叶子结点上添加服务器, 问最少添加多少服务器。
借鉴之处
- 无根树转有根树
- 结合并查集的思想
- 找第k个父亲可以用for 1 to k来实现。
- dfs的时候要记录节点的父亲,连接的不是它的父亲才便利
-
void dfs(int u,int f,int d)//节点,父亲,深度
{
fa[u] = f;
int len = gr[u].size();
if(len == 1 && d > k)node[d].push_back(u);
for(int i = 0 ; i < len ;i++) {
int v = gr[u][i];
if( v != f)dfs(v,u,d+1);
}
}
按深度遍历的方法:如果当前节点的大小是1,就说明到了叶子节点。dfs的时候记录深度 放入node中
树上距离转化为深度问题。因为只能在父节点放客户端。
UVA1398 Meteor
大意: 给出每颗流星初始位置及变化(以向量形式,即每单位时间x变多少,y变多少),告诉你一个框(1,1)到(w,h) 求同时刻最多看到多少星星(看的时间可以为小数)。 输入:输入数据第一行:数据组数。随后每组数据,第一行w,h,第二行:流星个数n,其他行:n个流星的信息。 输出:每组数据一行,为所求答案。
题目价值
-
转化:
- 把二维的线变为一维的区间。发现流星的轨迹没有什么用处,所以根据时间转化为区间
- 把区间变为左右端点,左端点表示一个区间正在进入,所以+1,右端点表示一个区间正在出去,-1;
- 如果两个区间左端点和右端点重合。就需要考虑怎么算是正确的:如果先算左端点,则,先+1,又+1,ans取了max,答案是2错误。如果先算右端点,先+1,-1,+1,答案是1正确;
- 前提是你这么写
if(event[i].kind == 0) ans = max(ans,++sum);
else sum--;
如果最后再来取答案会怎么样呢? 因为要取过程中的max所以不能最后统计。
UVA1330 City Game
大意:一块长N×宽M大小的网格矩形,其中可能有些网格已被占用,用R表示;有些则是空地,用F表示。求最大的由F组成的矩阵面积乘3
题目价值
- 递退思想
- 扫描思想
具体内容
- 如何用递退的方式得到left,right,up的信息?
- up[i][j] = up[i-1][j]+1;
- l[i][j] = max(l[i-1][j],lo + 1);
- r[i][j] = min(r[i-1][j],ro - 1);
然后从左到右一路扫 描下去。
细节很多。[总结题外话]如果是字符串 ,从0开始比较好。。。。。。UVA1382 Distant Galaxy
大意:
给出平面上的n个点,找一个矩形,使得边界上包含的点尽可能地多。
题目价值
- 部分枚举,来得到其他信息
- 前缀和
- 递推思想
- 关键比较
- 数组明确分工,明确各个数组的意义。
善用注释
UVA1326 Jurassic Remains
大意:给定n个由大写字母组成的字符串,尽量选择多的串,使得每个大写字母都能出现偶数次。
题意转换: 用二进制表示ABC…..Z中的情况1表示为奇数,0表示为偶数。=> 求尽量多的数,使它们异或和为0。^相同为0,不同为1。
题目价值
- 位运算
- 取某一位看是否为1:if(i&(1<< j ) ) i的第j位是否为1
- 计算二进制下1出现的次数:
int bitcount(int x){return x == 0 ? 0 : bitcount(x>>1) + (x&1);}
- 枚举子集:
通用格式:
for(int i =0; i<(1<<n); i++) //将1左移n位,其值为2^n
{
int cot =0;
for( int j =0; j<n; i++)
{
if(i&(1<<j)) 就搞事情;// 在当前的情况下,第j个杯子是否被选中呢?即i的第j位是不是1?
}
}
这里的运用:
for (int i = 0;i < (1<<n1);i++) {
int x = 0;
//i的哪一位是1就表示选了第个串。
for (int j = 0;j < n1;j++) if(i & (1 << j)) x ^= a[j];
if(!table.count(x) || bitcount(table[x]) < bitcount(i)) table[x] = i;
}
//x表示选择后字母的状况
//table[x]是答案的选择状况
- 中途相遇法:把串拆成两部分,这样就不用管每个部分的字符串的奇偶,只要两个状态相同加以来一定是偶数。
省选系列
[SCOI2009]最长距离
题义:
一个n×m的01矩阵,1表示有障碍物,能移走t个障碍。如果两个方格能走到,它们间的距离就是欧几里德距离。求它们之间最大距离
题目价值
学会转化:
最短路径算法可以延申到其他求最少的题目中,不过把道路之间的权值变成题目要求的东西。
这里移走t块石头,就可以当作权值。题目转化为:移走最少的石头,使两点间距离最大。
解决方法就是求出最少要移多少石头从(i,j)到(x,y),要小于等于t,然后比较他们之间的欧几里德距离,取个max就好了。
code不是重点
NOI系列
[NOI2015]程序自动分析
大意:假设有一个数组 A。给出 n 条限制,每一条限制形如< ai, bi ,ei >,
若 ei=1 则表示 A[ai]=A[bi],
若 ei=0 则表示 A[ai] A[bi]。
问是否存在使得所有限制均满足的数组 A。
考点
- 并查集
离散化
题目价值
- 学会离散。排序去重编号,然后查找位置(二分查找而不要总想着o(1)查表)。