7.16成外考试

那么就开始了:

蒟蒻表示不会。。。。这个题真是越来越难

1、选值

select.cpp/in/out/1s/256M

【题目描述】

给定n个数,从中选出三个数,使得最大的那个减最小的那个的值小于等于d,问有多少种选法。

【输入格式】

第一行两个整数n,d;

第二行n个整数。数据保证ai单调递增。

【输出格式】

输出一个整数表示满足条件的选法。

【输入输出样例】

select.in

select.out

样例1

4 3

1 2 3 4

4

样例2

4 2

-3 -2 -1 0

2

样例3

5 19

1 10 20 30 50

1

【数据范围】

对于40%的数据,1≤n≤103,1≤d≤104,abs(ai)≤104

对于100%的数据,1≤n≤105,1≤d≤109,abs(ai)≤109

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 long long num[100005];
 4 int main(){
 5     freopen("select.in","r",stdin);
 6     freopen("select.out","w",stdout);
 7     int n,d;
 8     cin>>n>>d;
 9     for(int i=1;i<=n;i++) scanf("%lld",&num[i]);
10     long long sum=0;
11     for(int i=1;i<=n-2;i++){
12         int l=i,r=n,mid;
13         long long val=d+num[i];
14         while(l<r){
15             mid=(l+r)>>1;
16             if(num[mid]>val) r=mid-1;
17             else if(num[mid]<val) l=mid+1;
18             else break;
19         }
20          while(num[l+1]<=val&&l+1<=n) l++;
21          while(num[l]>val&&l>=1) l--;
22         if(l-i<2) continue;
23         sum+=((long long)(l-i)*(long long)(l-i-1))/2;
24     }
25     cout<<sum<<endl;
26     return 0;
27 }

你先排序一下。当确定最大值为aj时, 用lower_bound找找前面大于等于aj-d的第一个数ai,因此我们可以在[i,j-1]中任选两个数作为一个组合,对答案的贡献为 c(j-i,2)。

但是实际上我做的时候用了一个差分数组,结果时间复杂度只比暴力快了一点点。。。。。QWQ

记得一定要用long long!!!!!!!!

2、遛狗

dog.cpp/in/out/1s/256M

【问题描述】

wkr养了一条狗,有一天把它带出来遛,路过一片玉米地,他的狗用一种很萌的眼神告诉他饿了(狗要吃玉米?!暂且不讨论这个问题……)。wkr没办法,只好带他进去偷,不过为了不被发现,他们只能往下、左、右三个方向走(有联系吗?……),走过的点上如果有玉米,他们就会全部偷走,然后那里的玉米就木有了。这是一个高端的农场,某些点会设有机器人,当你走到这些机器人的时候会掉落一定的玉米(然后就消失了),然后这个机器人就不再起作用了。

wkr想到反正都来了,不如多偷一点,所以他想知道从第一行任意一个位置开始,一直到最后一行任意一个位置结束,最终他最多能得到多少的玉米。

【输入描述】

第 1 行一个整数,N,表示 N×N 的玉米地

第 2 ~ n+1 行,每行 N 个整数,Aij 表示第 i 行 j 列上的玉米数,如果 Aij 为负数,表示遇到机器人,必须要掉落 |Aij| 的玉米数。相邻整数用一个空格隔开。

【输出描述】

输出文件一行一个整数,最后获得的玉米数。

【样例】

dog.in

dog.out

样例1

3

5 0 8

1 1 3

-10 0 -10

18

样例2

3

5 -10 -10

5 -5 20

20 -5 -5

45

【样例解释】

样例1解释:(1,1) → (1,2) → (1,3) → (2,3) → (2,2) → (2,1) → (2,2) → (3,2) → 结束

样例2解释:(1,1) → (2,1) → (2,2) → (2,3) → (2,2) → (2,1) → (3,1) → 结束

【数据范围】

对于 10%的数据:N<=3

对于 30%的数据:没有机器人(即全为非负数)

对于所有数据:N<=50,-10000<=Aij<=10000。

/*http://blog.csdn.net/jiangzh7
By Jiangzh*/
#include<cstdio>
#include<algorithm>
const int N=50+10;
const int inf=0x3f3f3f3f;int n,a[N][N];
int sum[N][N];
int f[N][N];
bool cal[N][N];void read()
{scanf("%d",&n);for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
}int walk(int x,int y)
{if(x==n){int lmax,rmax,res=0;lmax=rmax=a[x][y];int l=y,r=y;while(l>1){l--;lmax=std::max(lmax,sum[x][y]-sum[x][l-1]);}while(r<n){r++;rmax=std::max(rmax,sum[x][r]-sum[x][y-1]);}res=lmax+rmax-a[x][y];//printf("%d %d : %d\n",x,y,res);return res;}if(cal[x][y]) return f[x][y];f[x][y]=-inf; cal[x][y]=1;for(int m=1;m<=n;m++){int tmp=walk(x+1,m);int l=y,r=y;if(l>m) l=m; else if(r<m) r=m;int lmax=sum[x][m]-sum[x][l-1];int rmax=sum[x][r]-sum[x][m-1];while(l>1){l--;lmax=std::max(lmax,sum[x][m]-sum[x][l-1]);}while(r<n){r++;rmax=std::max(rmax,sum[x][r]-sum[x][m-1]);}int res=lmax+rmax-a[x][m];f[x][y]=std::max(f[x][y],res+tmp);//printf("(%d,%d) : lmax=%d   rmax=%d   res=%d   f[x][y]=%d\n",x,y,lmax,rmax,res,f[x][y]);
    }return f[x][y];
}void work()
{for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)sum[i][j]=sum[i][j-1]+a[i][j];int res=-inf;for(int i=1;i<=n;i++) res=std::max(res,walk(1,i));printf("%d",res);
}int main()
{freopen("dog.in","r",stdin);freopen("dog.out","w",stdout);read();work();return 0;
}
/*
3
-5 -10 -20
-5 -10 -20
-5 -10 -20
*/

做过方格取数的同学可能看见这一题就有点欣喜若狂了,方格取数直接二维dp就ok了

但是这一题略微有一点差别,他可以向三个方向走,这样就不满足dp的无后效性了

有10分的小数据,是在不会了可以全部 if 搞定

还有30分没有机器人,没有负数,并且因为在每一行内可以向左向右,那么我们就可以把这一行全部取完再去取下一行,仍然全部取完……这样我们就可以把整个地图取完,那么肯定是最大的。这样30分轻松得到(这里的 30 分和上面的 10 分有重叠……)

最后就是100分算法了:

这一题我们抽象一下,就是在每一行找一个区间,相邻两行之间所找的区间必须要有重叠的部分,然后求出一个最有方案值。

对于每一个选取的区间[L,R],设他是从M处走下去的,那么就肯定满足M∈[L,R],也就是L<=M, R>=M,如图

上面相当于是已知当前选的[L,R],然后去找下一个区间的进入点 M,我们倒着来想,我们枚举每一行的入点,找出所有的方案(类似八皇后的全排列),如图

然后再此基础上来确定每一行的最优区间,既然要满足 M∈[L,R],那么只要 L>M,即

,我们就要让L=M,R 同理,只要 R<M,就让 R=M。

好了,这是找到满足当前方案的合法区间,但是不一定是一个最优的(可能L 再向左或者 R 再向右能使整个区间值更大),所以我们只需要让 L 和 R 分别向左和向右来确定最大区间的 L 和 R 的位置,然后就能够得到最优值了。

至于怎么确定 L 和 R 的位置,同学们可以自己思考,这里我介绍一下我的方法。我们把区间[L,R]分成 [L,M] + [M,R] - {M} (M 为当前行到下一行的入点位置),那么我们维护一个 L 和 R 指针,在维护一个 Lmax 和 Rmax,先让 L 从前面确定好的位置向左,每次求出[L,M]的和取 Lmax 取最大值,R 同理,最后区间的最优值就为 Lmax+Rmax-M。

再看看复杂度,O(N^N),显然是不能承受的,不过很明显可以感觉到,特别是越到下面,他们重复计算的次数就越多,所以想到记忆化。复杂度就不分析了,大概是 O(N^4)或者 O(N^3)的样子。

3、树上博弈

tree.cpp/in/out/1s/256M

【问题描述】

有一棵n个点的有根树,他有m个叶子结点(叶子结点是那些没有孩子的结点)。边由父亲指向孩子。数字1到m被分配到每一个叶子中。每一个叶子有一个数字,并且每一个数字恰好被分配到一个叶子中。

刚开始的时候根部有一个棋子。两个玩家轮流移动棋子,每一步都会将这个棋子向他的某一个孩子移动;如果玩家不能再移动棋子了,那么游戏结束。游戏的结果就是棋子所在叶子上面的数字。游戏的先手想要这个数字最大化,而后手想要这个数字最小化。

山巴布里想要给这些叶子分配数字使得最终结果最大,而马族塔想要给这些叶子分配数字使得最终结果最小。那么当山巴布里来分配数字的时候游戏结果会是多少?马族塔分配的时候又是多少呢?山马布里和马族塔并不参加游戏,而是另外两个非常聪明的人来参加游戏。

【输入描述】

单组测试数据。

第一行有一个整数n (1≤n≤2*10^5),表示树中结点的数目。

接下来n-1行,每一行两个整数ui 和 vi (1≤ui,vi≤n) ,表示树中的边,由ui指向vi。

输入保证是一棵有根树,而且根是1。

【输出描述】

输出两个整数表示最大值和最小值,以空格分开。

【样例】

tree.in

tree.out

样例1

5

1 2

1 3

2 4

2 5

3 2

【样例解释】

样例解释:在这个样例中,树有三个叶子:3,4和5。如果把数字3分配给3号结点,那么第一个选手就能够让棋子到达那儿,最终结果就是3。另一方面,很明显,无论怎么分配数字,第一个选手让棋子达到最小数字是2。

【数据范围】

对于30%的数据,1≤n≤2000

对于50%的数据,1≤n≤20000
对于100%的数据,1≤n≤2*10^5,1≤ui,vi≤n

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;const int N=200010, INF=1000000000;
int n, mi, all;
int head[N], f[N], g[N], chu[N];struct Edge{int to,next;
}e[N<<1];inline void add(int u,int v){e[++mi] = (Edge){v,head[u]};head[u] = mi;
}void dfs1(int u,int fa,int dep){for(int p=head[u]; p; p=e[p].next) if(e[p].to!=fa) dfs1(e[p].to, u, dep+1);if(!chu[u]) all++, f[u]=g[u]=1;else{if(dep&1){                    // 讨论这一步该谁选  f[u] = INF;for(int p=head[u]; p; p=e[p].next) if(e[p].to!=fa){f[u] = min(f[u], f[e[p].to]);        // 一号管理员控制  g[u] += g[e[p].to];                // 二号管理员控制
            }}else{g[u] = INF;for(int p=head[u]; p; p=e[p].next) if(e[p].to!=fa){f[u] += f[e[p].to];g[u] = min(g[u], g[e[p].to]);}}}}int main(){freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);scanf("%d",&n);for(int i=1, u, v; i<n; ++i){scanf("%d%d",&u,&v);add(u,v); add(v,u);chu[u]++;}dfs1(1,0,1);printf("%d %d\n",all-f[1]+1, g[1]);
}

一号管理员想让最后的数尽量大,这正好符合一号选手的思路,而与二号选手相违背,而且这一次该一号选手选还是该二号选手选只与深度有关。因此设f[i],当一号选手选时,f[i]表示在i的子树内,最少有几个数比最终结果大,f[u]= min(f[v]),这样,当他进入v这个子树中时,管理员可以把u子树内的前f[v]大都放在v子树中,一号选手的最终答案就是u子树的前f[v]大;当二号选手选时,f[i]表示在i的子树中,最多有几个数比最终结果小,f[u]=Σ(f[v]),这样,二号选手在知道 u 子树中的数字分布情况下尽量往小走。转移方程:(v 为 u 的孩子)

该一号选手选时: f[u] = min(f[v])

该二号选手选时: f[u] = Σ f[v]

二号选手为什么是Σ f[v] ,而不是max(f[v]) 呢?因为在当前,他有多棵子树可以选,他当然选最大值最小的那棵(相当于更大的值因为不选而废了),所以就用 Σ 了(还是难理解?那我没办法了)

二号管理员控制时就反过来, f[i] 分别表示该一号选手选时当前比最终结果小的数最多有多少,当二号选手选时表示当前结果比最终结果少的数最多有多少,转移方程类似。

这种在不同时刻 f 的意义不同的,状态表示还这么巧妙的题真强。

记得点赞推荐哦!!!

三玖天下第一!!!!!!!

转载于:https://www.cnblogs.com/fakerOrz/p/11197068.html

蒟蒻7.16题解(选值+遛狗+树上博弈)相关推荐

  1. 蒟蒻的HNOI2017滚粗记

    蒟蒻的第一次省选,然而并没有RP爆发... Day 1: 8:00开考,(然而密码错误是什么鬼).跌跌撞撞,8:40终于拿到纸质试题. { T1:作为一名没有学过Splay的蒟蒻,考场上真的被出题人感 ...

  2. 蒟蒻君的刷题日记Day12(线段树专题T4):P8082 [COCI2011-2012#4] KEKS 线段树版题解

    解题思路 看题解区的大佬们用的都是单调栈,本蒟蒻献上一篇线段树题解. 整个数最大,首先位数是确定的,则肯定优先考虑高位大小. 大体思路就是从前向后依次求出每一位的值(好像是废话). 对于第 iii 位 ...

  3. USACO 简易题解(蒟蒻的题解)

    蒟蒻难得可以去比赛,GDOI也快到了,还是认真刷题(不会告诉你之前都在颓废),KPM 神犇既然都推荐刷USACO, 辣就刷刷. 现在蒟蒻还没刷完,太蒟刷得太慢,so 写了的搞个简易题解(没代码,反正N ...

  4. [颓废史]蒟蒻的刷题记录

    QAQ蒟蒻一枚,其实我就是来提供水题库的. 以下记录从2016年开始. 1.1 1227: [SDOI2009]虔诚的墓主人 树状数组+离散化 3132: 上帝造题的七分钟 树状数组 二维区间加减+查 ...

  5. 蒟蒻成长之路(持续更新)

    蒟蒻成长之路 (这个玩意只是闲着写写, 写给自己看的) 开始 开始日期:2023年3月23日20:55:24 内容 主要记录一些做题日常和快乐的学校生活 初一:2022~2023 Day1--2023 ...

  6. 蒟蒻的五周总结(解释引用)《挑战》

    一:尺取法: 解释摘自:(12条消息) 尺取法 - 详解 + 例题模板(全)_lxt_Lucia的博客-CSDN博客_尺取法 引用:顾名思义,像尺子一样取一段,借用挑战书上面的话说,尺取法通常是对数组 ...

  7. 蒟蒻的python 学习笔记 ——北京理工大学嵩天mooc(有时间就看就更新,尽量让笔记容易懂,蟹蟹各位大神不吝赐教)

    蒟蒻的python 学习笔记 前言 课一:python语言程序设计 第一周:python 基本语法元素 1.1 程序设计基本方法 1.2 python 环境配置 1.3 实例1:温度转换 1.4 py ...

  8. BZOJ 4636 蒟蒻的数列

    4636: 蒟蒻的数列 Time Limit: 30 Sec  Memory Limit: 256 MB Submit: 618  Solved: 271 [Submit][Status][Discu ...

  9. CCF NOI WC 2019 游记 by.一个云南蒟蒻

    序 我是一个来自云南的蒟蒻. 大约是2018年八月份,我开始正式学习OI.在此之前,我约莫一直听说这世上有这么一种神奇的东西,兴许也曾路过,却从未走进这扇门来(大概是百度过,兴许是被铺天盖地的广告劝退 ...

  10. Linux中如何将文件dump成16进制值

    http://www.cnblogs.com/bcxx_qin/archive/2009/05/06/1450596.html 在linux中有多种方式可以将文件dump成16进制显示,也可以将16进 ...

最新文章

  1. 未来2年,程序员如何吊打高学历工程师?服气!
  2. 干货丨从线性回归到无监督学习,数据科学家需要掌握的十大统计技术
  3. CG CTF WEB md5 collision
  4. 三相pmsm矢量控制仿真模型_学术|基于新型滑模观测器的永磁同步电机无传感器矢量控制系统...
  5. SQL2005 express升级到2008企业版解决4096限制问题
  6. Spring Android 1.0.0.M3 发布
  7. 最新linux 5,Linux 5.5 正式发布
  8. 时间序列分析python课程论文_python时间序列分析
  9. 360浏览器打开Axure
  10. 特别推荐BLOG(一) 程序猿DD的博客
  11. EasyPoi如何使用注解导出,并且添加自增序号?
  12. SYSLINUX中文介绍
  13. ntfs磁盘格式是什么?NTFS如何读写Mac硬盘?
  14. 红旗linux考试,红旗Linux认证考试介绍
  15. dell服务器装独立显卡无显示输出,dell服务器设置独立显卡(dell服务器加显卡)...
  16. Python-数据的多种存储形式
  17. 【C++算法模板】日期类型题目:节假日
  18. 到底怎么买保险?附保险配置实战
  19. 4.6 基于反熵的状态同步
  20. Xshell6 中文不限时版下载(免密匙)及安装教程

热门文章

  1. 笔记-as/400的CL命令
  2. R|数据处理|merge数据详解
  3. 初入职场,如何快速脱颖而出?
  4. webpack4打包vue前端多页面项目
  5. 两分钟实现安全完备的登录模块
  6. C# 字段、属性、成员变量
  7. C# mvc4.0 MD5测试
  8. 使用Asp.net MVC源代码调试你的应用程序
  9. php装curl拓展出错
  10. Android studio 怎么使用已经下载好的Android SDK ?