[ 杂题总结 ]

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)查表)。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐行tag

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值