今天是钟皓曦老师的讲授~

今天的题比昨天的难好多,呜~

T1

我们需要找到一个能量传递最多的异构体就好了;

整体答案由花时间最多的异构体决定;

现在的问题就是这么确定一个异构体在花费时间最优的情况下所花的时间是多少;

我们去枚举一个异构体 i,以这个异构体为分界线将其分成左右两部分,设左半部分的异构体的能量和为 sum;

如果 sum > ( i-1 ) * v,v * n - sum(右部分) < 0 ,说明左边的能量是够的,不需要再输入能量了,但是右部分却不够,所以我们需要从左边往右边输送能量,那么输送的能量的多少就是 i 这个异构体的贡献;

做法:去枚举每一个 i,考虑这个节点它的作用(往哪里传递能量) ,注意一共四种情况:

1. 左边多,右边少;那么 i 节点的作用就是把左边多余的能量传递到右边;

2. 左边少,右边多;那么 i 节点的左右就是把右边多余的能量传递到左边;

3. 左边多,右边也多;也就是说 i 这个点少了好多能量,我们就要把两边多余的能量搬到 i,时间取决于耗时长的一遍:max(x,y);

4. 左边少,右边也少;也就是说 i 这个点多了好多能量,我们要把多余的能量搬到两边,但是注意每一时刻只能搬一点能量,所以需要 x+y 的时间;

所以这个题就做完了;

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm> using namespace std; const int maxn=; int n,z[maxn]; long long sum[maxn]; void read()
{
scanf("%d",&n);
for (int a=;a<=n;a++)
scanf("%d",&z[a]);
} long long work()
{
for (int a=;a<=n;a++)
sum[a] = sum[a-]+z[a];
if (sum[n]%n) return -;
long long ans=,v=sum[n]/n;
for (int a=;a<=n;a++)
{
long long l=sum[a-]-1ll*(a-)*v;
long long r=sum[n]-sum[a]-1ll*(n-a)*v;
if (l< && r<) ans=max(ans,-l-r);
ans=max(ans,max(abs(l),abs(r)));
}
return ans;
} int main()
{
read();
printf("%lld\n",work()); return ;
}

T2

语文太差了,还以为必须要从 1 走到 n,然后 100 -> 0(其实是玄学 RE);

没要求必须从左往右走?炸了~

我们从小到大排好序,这样的话我们选数的时候只需要考虑所选的数是不是前面的数的倍数就行了(因为前面的数一定是更前面所有数的倍数);

f [ i ] 表示已经取了第 i 个数了,我们去枚举前面选的那个数是多少,看是不是它的倍数就可以了:

f [ i ] = max ( f [ j ] ) + 1,a [ i ] 是 a [ j ] 的倍数;

这个题搜索写得好好像可以过。。

我们看到有个很重要的隐藏 bug:有 20% 的数据保证所有城市的数都不重复;

考虑到由于所选的数都是倍数关系,所以这些城市的数最多就 20 个不同的数!

那么我们可以先去重,然后如果一个数 a [ i ] 被选上了,那么和它相等的数也都要选上,这样才能保证最优嘛;

所以我们可以在此基础上搜索,或者按照上面说的那样 dp 一下,就可以过了;

然而不是正解?

正解:

我们可以开一个桶,记录每个数出现了多少次;

改造一下 dp:f [ i ] 我取出来的序列最后一个数等于 i 的情况下最长是多少;

那么接下来我们要取得的是 i 的倍数,所以我们就去枚举 i 的倍数,一直枚举到一百万就行了;

f [ k * i ] = max ( f [ i ] + cnt [ k * i ] );

我们不关心那个数是多少,我们只关心有多少个 。

#include<cstdio>
#include<cstdlib>
#include<cstring> using namespace std; const int maxn=; int n,cnt[maxn],f[maxn]; int main()
{
scanf("%d",&n);
for (int a=;a<=n;a++)
{
int v;
scanf("%d",&v);
cnt[v]++;
f[v]++;
}
int ans=;
for (int a=;a<=;a++)
if (f[a])
{
if (f[a]>ans) ans=f[a];
for (int b=a+a;b<=;b+=a)
if (cnt[b] && f[a]+cnt[b]>f[b]) f[b]=f[a]+cnt[b];
}
printf("%d\n",ans); return ;
}

T3

zhx:明天考试不考 2-SAT,真香~

最小值最大化,我们用二分;

我们二分答案 v,那么我们所选的任意两张卡牌的差值的绝对值都要大于 v;

假如我们有两组卡牌,他们的战斗力分别是 a1 , b1 和 a, b2

如果 a- a2 < v,那么说明 a1 和 a2 不能同时选,所以如果我们选了 a1  ,那么我们就只能选 b2 了,从 a1 向 b2 

这样能过 50% 的数据;

考虑到建边的时间复杂度是 O ( n2 ) 的,显然过不了 100% 的数据;

线段树优化建边 。

我们将这 2n 个数从小到大排序,假如现在我们考虑 ci ,需要和它建边的点一定是一个连续的区间;

发现这是一个区间加边的操作,怎么搞呢?

我们建一棵线段树,然后对线段树进行区间加边的操作,我们可以把线段树上的边也看做是图的一部分的话,那么我们就只需要建 log n 条边:

每次只需要加 log n 条边,总时间复杂度 O ( n log 2 n );

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<algorithm> using namespace std; const int BUF_SIZE = ;
char buf[BUF_SIZE], *buf_s = buf, *buf_t = buf + ; #define PTR_NEXT() \
{ \
buf_s ++; \
if (buf_s == buf_t) \
{ \
buf_s = buf; \
buf_t = buf + fread(buf, , BUF_SIZE, stdin); \
} \
} #define readint(_n_) \
{ \
while (*buf_s != '-' && !isdigit(*buf_s)) \
PTR_NEXT(); \
bool register _nega_ = false; \
if (*buf_s == '-') \
{ \
_nega_ = true; \
PTR_NEXT(); \
} \
int register _x_ = ; \
while (isdigit(*buf_s)) \
{ \
_x_ = _x_ * + *buf_s - ''; \
PTR_NEXT(); \
} \
if (_nega_) \
_x_ = -_x_; \
(_n_) = (_x_); \
} #define readstr(_s_) \
{ \
while (!isupper(*buf_s)) \
PTR_NEXT(); \
char register *_ptr_ = (_s_); \
while (isupper(*buf_s) || *buf_s == '-') \
{ \
*(_ptr_ ++) = *buf_s; \
PTR_NEXT(); \
} \
(*_ptr_) = '\0'; \
} #define readlonglong(_n_) \
{ \
while (*buf_s != '-' && !isdigit(*buf_s)) \
PTR_NEXT(); \
bool register _nega_ = false; \
if (*buf_s == '-') \
{ \
_nega_ = true; \
PTR_NEXT(); \
} \
long long register _x_ = ; \
while (isdigit(*buf_s)) \
{ \
_x_ = _x_ * + *buf_s - ''; \
PTR_NEXT(); \
} \
if (_nega_) \
_x_ = -_x_; \
(_n_) = (_x_); \
} #define wmt 1,(n<<1),1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 const int maxn=;
const int maxp=maxn+(maxn<<);
const int maxm=maxn+maxp+maxn*; int n,size,cnt,en,t,dfn[maxp],low[maxp],s[maxp],belong[maxp],pos[maxn]; bool instack[maxp]; struct edge
{
int e;
edge *next;
}*v[maxp],ed[maxm]; void add_edge(int s,int e)
{
en++;
ed[en].next=v[s];v[s]=ed+en;v[s]->e=e;
} struct rec
{
int v,p;
rec(){}
rec(int a,int b)
{
v=a;p=b;
}
}z[maxn]; bool operator<(const rec &a,const rec &b)
{
return a.v<b.v;
} void dfs(int p)
{
t++;
dfn[p]=low[p]=t;
instack[p]=true;
s[++size]=p;
for (edge *e=v[p];e;e=e->next)
if (!dfn[e->e])
{
dfs(e->e);
low[p]=min(low[p],low[e->e]);
}
else
{
if (instack[e->e]) low[p]=min(low[p],dfn[e->e]);
}
if (dfn[p]==low[p])
{
cnt++;
while (s[size]!=p)
{
belong[s[size]]=cnt;
instack[s[size]]=false;
size--;
}
belong[p]=cnt;
instack[p]=false;
size--;
}
} void build(int l,int r,int rt)
{
if (l==r)
{
add_edge(rt+(n<<),z[l].p<=n?z[l].p+n:z[l].p-n);
return;
}
int m=(l+r)>>;
build(lson);
build(rson);
add_edge(rt+(n<<),(rt<<)+(n<<));
add_edge(rt+(n<<),(rt<<|)+(n<<));
} void insert(int l,int r,int rt,int nowl,int nowr,int p)
{
if (nowl<=l && r<=nowr)
{
add_edge(p,rt+(n<<));
return;
}
int m=(l+r)>>;
if (nowl<=m) insert(lson,nowl,nowr,p);
if (m<nowr) insert(rson,nowl,nowr,p);
} bool check(int k)
{
en=;cnt=;
memset(v,,sizeof(v));
memset(dfn,,sizeof(dfn)); build(wmt); int r=,l=; for (int a=;a<=(n<<);a++)
{
int op,p=z[a].p;
if (p<=n) op=pos[p+n];
else op=pos[p-n];
while (r<=a && z[r].v <= z[a].v-k)
r++;
if (r<a && r>= && z[r].v > z[a].v-k)
{
if (op>=r && op<=a-)
{
if (op>r) insert(wmt,r,op-,z[a].p);
if (op<a-) insert(wmt,op+,a-,z[a].p);
}
else insert(wmt,r,a-,z[a].p);
}
while (l<=(n<<) && z[l].v < z[a].v+k)
l++;
l--;
if (l>a && l<=(n<<) && z[l].v < z[a].v+k)
{
if (op>=a+ && op<=l)
{
if (op>a+) insert(wmt,a+,op-,z[a].p);
if (op<l) insert(wmt,op+,l,z[a].p);
}
else insert(wmt,a+,l,z[a].p);
}
} for (int a=;a<=(n<<);a++)
if (!dfn[a]) dfs(a);
for (int a=;a<=n;a++)
if (belong[a]==belong[a+n]) return false;
return true;
} int main()
{
readint(n);
int minv=0x3f3f3f3f,maxv=-0x3f3f3f3f;
int x=;
for (int a=;a<=n;a++)
{
int v1,v2;
readint(v1);
readint(v2);
z[++x]=rec(v1,a);
z[++x]=rec(v2,a+n);
minv=min(minv,min(v1,v2));
maxv=max(maxv,max(v1,v2));
}
if (maxv-minv+ < n)
{
printf("0\n");
return ;
}
sort(z+,z+x+);
for (int a=;a<=(n<<);a++)
pos[z[a].p]=a;
int l=,r=;
while (l+!=r)
{
int m=(l+r)>>;
if (check(m)) l=m;
else r=m;
}
printf("%d\n",l); return ;
}

f [ i ][ j ]:表示第 i 位到第 j 位所能组成的最长回文子序列;

考虑怎么使序列更长?我们分别在两端加一个相同的字符不就好了?

所以我们枚举 i 之前,j 之后找一个相同的字符就好了;

f [ i ][ j ] +1 -> f [ k ][ l ];

时间复杂度 O(n4

考虑到 dp 有三种写法:

1. 自己算别人;

2. 别人算自己;

3. 记忆化搜索;

我们刚刚的写法是自己去算别人,现在我们来考虑用别人算自己;

如果用第 i 个字符:f [ i+1 ][ j ];

如果用第 j 个字符:f [ i ][ j-1 ];

如果第 i 个字符和第 j 个字符我们都用:f [ i+1 ][ j-1 ];

那么转移就是:f [ i ][ j ] = max ( f [ i+1 ][ j ] , f [ i ][ j-1 ] , f [ i+1 ][ j-1 ] ) ,s [ i ] == s [ j ];

zhx:我们发现这道题十分的水,所以来加强一下,问本质不同的回文字符串有多少个?

对于本质相同:aba 类型算一种:121,252,707……;

f [ k+1 ][ l-1 ] 内的字符串都会被重新再算一次;

所以我们只需要再从答案里减去 f [ k+1 ][ l-1 ] 就行了;

k 和 l 的位置可以预处理;

整体复杂度 O(n2);

做排列类型的 dp 题时,我们考虑把数从小到大一个一个插进去;

排列的性质:

我们随便从排列里取出一个前缀,它还是个排列;

f [ i ][ j ]:我们已经用 1~i 将前 i 个位置填好了,第 i 个位置是 j 的方案数是多少;

转移:f [ i ][ j ] -> f [ i+1 ][ k ]

分两组情况:

1. ai > ai+1 ,也就是说我们接下来插的这个数比之前插的数要小:

那么我们能填的数就是 1 ~ j-1(前一个填的数是 j),但是显然我们要填的这个数必然在前面已经用过了,会发生冲突,怎么办呢?

我们把 1~i 中大于等于 k 的数全部 +1 就好:

假如我们第六位插入一个 3,发现小于前一个插入的 5,那么我们让前面所有大于等于 3 的数全部加一,这样就空出一个 3 来了:

2 3 4 1 5

2 4 5 1 6 3;

2. ai < ai+1

道理是一样的,我们所插入的数的范围就变成了:j < k <= i+1(要大于前面插入的那个数,同时要在 i+1 以内)

转移方程:

1. ai > ai+1 :f [ i+1 ][ k ] = f [ i ][ j ] (k < j)

2. ai < ai+1 :f [ i+1 ][ k ] = f [ i ][ j ] (j < k <= i+1 )

时间复杂度:O ( n3 );

考虑到加一的时候我们可以前缀和优化,所以就优化成了 O ( n2 );

日常盲设状态:f [ i ][ j ] 表示选了 i 个点到了第 j 层的方案数;

发现这个状态没有办法转移。。。那怎么办呢?

换一个状态:f [ i ][ j ] :表示已经用了 i 个点,它们的深度都小于等于 j 的方案数;

答案就是:f [ n ][ n ] - f [ n ][ k-1 ];

考虑转移:

我们考虑拆根,去枚举左右结点个数:

有两种可能的答案:

[ i,i,i ] ,[ i-1,i,i+2 ]

对于第二种情况,如果出现了超过 2 个的情况,我们完全可以将它们拆成第一种的情况,所以第二种的数量一定是不超过 2 个的;

状态:

f [ i ][ j ][ k ] 我们已经处理完了 1~ i 这些数,用了 j 个 i-1,i,i+1,k 个 i,i+1,i+2 的方案数,注意 j 和 k 一定是小于等于 2 的;

转移:

用 l 个 i+1,i+2,i+3;

然后咕咕咕了qwq~

f [ i ][ j ][ k ]:表示在 i 轮结束之后,aj < ak 的方案数,j < k;

Σ ( j >k ) f [ q ][ j ][ k ];

但是交换 j,k 两个位置不仅仅是影响这两个位置的值,还会对后面的位置产生影响;

时间复杂度 O(n2);

对拍讲解现场:

随机生成树:

扫把图:

zhx AK做题方法:

前 10~ 15 分钟全部用来读题,包含手推样例;

然后我们选择一个合理的做题的顺序,一般来说是 1,2,3 的顺序,但是也不一定嘛qwq;

先写暴力,拿到保底分;

然后朝着 100 分的方向前进;

最后 15 分钟一定要丢掉键盘,静坐待亡检查一下自己有没有zz(数组开大开小,文件输入输出……)!

10月清北学堂培训 Day 4的更多相关文章

  1. 10月清北学堂培训 Day 7

    今天是黄致焕老师的讲授~ 历年真题选讲 NOIP 2012 开车旅行 小 A 和小 B 决定外出旅行,他们将想去的城市从 1 到 n 编号,且编号较小的城市在编号较大的城市的西边.记城市 i 的海拔高 ...

  2. 10月清北学堂培训 Day 6

    今天是黄致焕老师的讲授~ T1 自信 AC 莫名 80 pts???我还是太菜了!! 对于每种颜色求出该颜色的四个边界,之后枚举边界构成的矩阵中每个元素,如果不等于该颜色就标记那种颜色不能最先使用. ...

  3. 10月清北学堂培训 Day 5

    今天是廖俊豪老师的讲授~ T1 第一次想出正解 30 pts: k <= 10,枚举如何把数放到矩阵中,O ( k ! ): 100 pts: 对于矩阵的每一列,我们二分最小差异值,然后贪心去判 ...

  4. 10月清北学堂培训 Day 3

    今天是钟皓曦老师的讲授~ zhx:题很简单,就是恶心一些qwq~ T1 别人只删去一个字符都能AC,我双哈希+并查集只有40?我太菜了啊qwq 考虑到越短的字符串越难压缩,越长的字符串越好压缩,所以我 ...

  5. 10月清北学堂培训 Day 2

    今天是杨溢鑫老师的讲授~ T1 物理题,不多说(其实是我物理不好qwq),注意考虑所有的情况,再就是公式要推对! #include<bits/stdc++.h> using namespa ...

  6. 10月清北学堂培训 Day 1

    今天是杨溢鑫老师的讲授~ T1 1 题意: n * m 的地图,有 4 种不同的地形(包括空地),6 种不同的指令,求从起点及初始的状态开始根据指令行动的结果. 2 思路:(虽然分了数据范围但是实际上 ...

  7. 7月清北学堂培训 Day 3

    今天是丁明朔老师的讲授~ 数据结构 绪论 下面是天天见的: 栈,队列: 堆: 并查集: 树状数组: 线段树: 平衡树: 下面是不常见的: 主席树: 树链剖分: 树套树: 下面是清北学堂课程表里的: S ...

  8. 8月清北学堂培训 Day6

    今天是杨思祺老师的讲授~ 图论 双连通分量 在无向图中,如果无论删去哪条边都不能使得 u 和 v 不联通, 则称 u 和 v 边双连通: 在无向图中,如果无论删去哪个点(非 u 和 v)都不能使得 u ...

  9. 8月清北学堂培训 Day2

    今天是赵和旭老师的讲授~ 背包 dp 模型 背包 dp 一般是给出一些“物品”,每个物品具有一些价值参数和花费参数,要求 在满足花费限制下最大化价值或者方案数. 最简单几种类型以及模型: 0/1背包: ...

随机推荐

  1. # RESTful登录(基于token鉴权)的设计实例

    使用场景 现在很多基于restful的api接口都有个登录的设计,也就是在发起正式的请求之前先通过一个登录的请求接口,申请一个叫做token的东西.申请成功后,后面其他的支付请求都要带上这个token ...

  2. App功能测试点总结

    1.手机操作系统android(谷歌).ios(苹果).Windows phone(微软).Symbian(诺基亚).BlackBerry OS(黑莓).windows mobile(微软),目前主流 ...

  3. AngularJS在IE下页面缓存问题

    问题: 在使用AngularJS发出请求(GET)获取服务端数据,然后再绑定到页面中,你会发现在IE中总是显示原来的数据结果.这时候我们就会知道,IE做了缓存. 解决办法: 我们可以在AngularJ ...

  4. Vuex 刷新后数据丢失问题 Typescript

    问题描述:Vuex保存的数据在页面刷新后会全部丢失清除 问题解决方案:使用sessionstorage进行保存,在页面刷新时保存至sessionStorage,页面在加载时再进行填充   (另有vue ...

  5. python实现ssh及sftp功能

    1.在Linux上我们通过scp命令实现主机间的文件传送,通过ssh实现远程登录 ,比如 我们经常使用的xshell远程登录工具,就是基础ssh协议实现window主机远程登录Linux主机 下面简单 ...

  6. Date与String的相互转换

    构造函数 日期:new Date();//获取当前日期,精确到毫秒. 日期:new Date(long date);//即1970 年 1 月 1 日 00:00:00 GMT(Greenwich M ...

  7. ES Client

    关于 ElasticSearch的学习参见:ELK | wjcx_sqh 本文分别学习 .Net | Java 下操作 ES: .Net 目前主流的 .Net 客户端有 2 种: PlainElast ...

  8. 五、MySQL系列之高级知识(五)

    本篇 主要介绍MySQL的高级知识---视图.事件.索引等相关知识: 一.视图 在学习视图时我们需要什么是视图,视图有哪些好处以及视图的相关操作: 1.1  什么是视图? 关于视图通俗来讲就是一条se ...

  9. null和空的区别

    python中None和Null的区别 首先了解python对象的概念 python中,万物皆对象,所有的操作都是针对对象的. 那什么是对象?5是一个int对象,‘oblong’是一个str对象,异常 ...

  10. Mybatis3.1-[tp_36-37]-_映射文件_select_resultMap关联查询__分步查询传递多列值&fetchType_discriminator鉴别器

    _分步查询传递多列值&fetchType_discriminator鉴别器 笔记要点出错分析与总结 Department.java bean public class Department { ...