T1

以下的LIS代指最长不降子序列。

考场看到取模,便想到了之前写过的Medain,取模操作让序列分布均匀,对应到本题上,既然是求LIS,那它应该是有循环节的,后来打表证实确实是有。

然后,我码了个BIT优化LIS。觉得应该能拿30pts,然后就傻逼的跳了,其实正解已经想的差不多了,但是本着先把暴力分都拿到的原则,就跳了 我是sb

考场想法:

既然有循环节,那么就只需要把整个序列拆成三部分分别为A,B,C,其中A为包含一个循环节的最短的那一段序列,B全是循环的,C是最后那一段不完全的循环节,如果有的话。

那么就只需要对A求一下LIS,并记录最优答案是从那个位置转移过来的,多个的话全都记,然后看B中有多少个循环节,就对答案产生多少贡献,最后再对记录下来的求一遍LIS,然后对应到C上,看能拿多少。

看似正确,然而我没细想,假了,或者说我的打法假了,比如下面这组数据:

12

134 33 107 69 41

生成序列为:

134 32 16 20 34 35 0 28 32 16 20 34

很显然,LIS长度为5,但我的会输出4,因为它在A中求了个4,选的是 16,20,34,35,导致在C中选不了,但显然,最优应该是在A中选16,20,28,然后在C中32,34,LIS长度为5。

然而考试的时候也没调出来,30pts的也没交上,只能说是活该吧

正解:

就是找循环节,然后一顿乱搞,把循环节接150遍,其他的贡献都是1。

我的那份调了半个下午没调出来,所以换了做法

pdf上的矩阵快速幂不会,也懒的粘了,就这样吧。

Code
#include<cstdio>
#define MAX 1000010
#define re register
namespace OMA
{
long long n,ans;
int t,a,b,c,d,m,len,xam;
int tmp[MAX],pos[MAX];
inline int max(int a,int b)
{ return a>b?a:b; }
class BIT
{
private:
int tree[MAX];
inline int lowbit(int x)
{ return x&-x; }
public:
inline void insert(int x,int lis)
{
for(re int i=x; i<=xam; i+=lowbit(i))
{ tree[i] = max(tree[i],lis); }
}
inline int query(int x)
{
int res = 0;
for(re int i=x; i; i-=lowbit(i))
{ res = max(res,tree[i]); }
return res;
}
}BIT;
signed main()
{
scanf("%lld%d%d%d%d%d",&n,&t,&a,&b,&c,&d);
if(n==1)
{ printf("1\n"); return 0; }
tmp[1] = t;
for(re int i=2; i<=n; i++)
{
xam = max(xam,tmp[i] = (a*tmp[i-1]*tmp[i-1]+b*tmp[i-1]+c)%d);
if(pos[tmp[i]])
{ len = i-pos[tmp[i]],m = i-1; break ; }
pos[tmp[i]] = i;
}
xam += 1;
ans = (n-m)/len-150,n = (n-m)%len+len*150+m;
for(re int i=m+1; i<=n; i++)
{ tmp[i] = tmp[pos[tmp[m+1]]+i-m-1]; }
int lis = 0;
for(re int i=1; i<=n; i++)
{
tmp[i] += 1;
int res = BIT.query(tmp[i])+1;
BIT.insert(tmp[i],res);
lis = max(lis,res);
}
printf("%lld\n",ans+lis);
return 0;
}
}
signed main()
{ return OMA::main(); }

算了,还是贴一下,虽然没有意义

矩阵快速幂解法

T2

一看就不太可做,留在了最后,瞎打了个背包就没看了,然后接着去调T1了。

别人的想法:

同余最短路,能拿90pts,但好像是假的,然而这玩意我都听都没听过,更别提考场写出来

正解:

%%%沈学长。

是个dp,还没写出来,所以先咕了。

dp实质上是在一个图上跑,平常的dp都是有拓扑序,所以可以直接for循环来转移,想这种出现环的,需要跑个最短路来转移。

Code
咕咕咕

T3

考场直接树剖+线段树,然后打着打着发现思路卡壳了,没继续往下想,因为T1自己的想法还没打,所以干脆拿树剖求了个LCA,丢了个暴力就跑回T1了。

正解:

就是个线段树。

首先不难发现,一个节点 \(u\) 的权值,只有可能对自己的子树产生贡献,所以当一个节点 \(u\) 被修改之后,先用 \(u\) 的权值去更新 \(u\) 的子树,然后去暴力跳 \(u\) 的爹 \(fa\) ,那么\(fa\) 的子树中,除去 \(u\) 的子树那一部分都可以用 \(fa\) 的权值去更新,如果 \(fa\) 的子树在修改前就已经有黑点的话,就说明 \(fa\) 的父亲们或者说祖先之前肯定更新过了子树,就不再接着跳了。

说白了就是区间修改+单点查询

Code
#include<cstdio>
#include<cstring>
#include<climits>
#define MAX 100010
#define re register
#define INF INT_MIN
int n,m;
int w[MAX];
bool vis[MAX];
struct graph
{
int next;
int to;
}edge[MAX<<1];
int cnt=1,head[MAX];
inline void add(int u,int v)
{ edge[++cnt] = (graph){head[u],v},head[u] = cnt; }
namespace FTC
{
int fa[MAX],size[MAX],dfn[MAX];
inline void dfs(int u,int fat)
{
size[u] = 1,dfn[u] = ++cnt,fa[u] = fat;
for(re int i=head[u],v; i; i=edge[i].next)
{
v = edge[i].to;
if(v!=fat)
{ dfs(v,u); size[u] += size[v]; }
}
}
}using namespace FTC;
namespace OMA
{
inline int max(int a,int b)
{ return a>b?a:b; }
class Segment_Tree
{
private:
struct TREE
{
int xam;
int l,r;
int tag;
TREE()
{ xam = -1; }
}st[MAX<<2];
inline int ls(int p)
{ return p<<1; }
inline int rs(int p)
{ return p<<1|1; }
inline void Push_up(int p)
{ st[p].xam = max(st[ls(p)].xam,st[rs(p)].xam); }
inline void Push_down(int p)
{
if(st[p].tag)
{
st[ls(p)].xam = max(st[ls(p)].xam,st[p].tag);
st[ls(p)].tag = max(st[ls(p)].tag,st[p].tag);
st[rs(p)].xam = max(st[rs(p)].xam,st[p].tag);
st[rs(p)].tag = max(st[rs(p)].tag,st[p].tag);
st[p].tag = 0;
}
}
public:
inline void build(int p,int l,int r)
{
st[p].l = l,st[p].r = r;
if(l==r)
{ return ; }
int mid = (l+r)>>1;
build(ls(p),l,mid),build(rs(p),mid+1,r);
}
inline void update(int p,int l,int r,int val)
{
if(l>r)
{ return ; }
if(l<=st[p].l&&st[p].r<=r)
{ st[p].xam = max(st[p].xam,val); st[p].tag = max(st[p].tag,val); return ; }
Push_down(p);
int mid = (st[p].l+st[p].r)>>1;
if(l<=mid)
{ update(ls(p),l,r,val); }
if(r>mid)
{ update(rs(p),l,r,val); }
Push_up(p);
}
inline int query(int p,int pos)
{
if(st[p].l==st[p].r)
{ return st[p].xam; }
Push_down(p);
int ans = INF,mid = (st[p].l+st[p].r)>>1;
if(pos<=mid)
{ ans = max(ans,query(ls(p),pos)); }
else
{ ans = max(ans,query(rs(p),pos)); }
return ans;
}
inline void modify(int u)
{
update(1,dfn[u],dfn[u]+size[u]-1,w[u]);
while(!vis[u]&&fa[u])
{
vis[u] = 1;
update(1,dfn[fa[u]],dfn[u]-1,w[fa[u]]);
update(1,dfn[u]+size[u],dfn[fa[u]]+size[fa[u]]-1,w[fa[u]]);
u = fa[u];
}
}
}Tree;
inline int read()
{
int s=0,w=1; char ch=getchar();
while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
return s*w;
}
signed main()
{
n = read(),m = read();
for(re int i=1; i<=n; i++)
{ w[i] = read(); }
for(re int i=1,u,v; i<=n-1; i++)
{ u = read(),v = read(); add(u,v),add(v,u); }
cnt = 0,dfs(1,0);
Tree.build(1,1,n);
for(re int i=1,u; i<=m; i++)
{
char s[10]; scanf("%s",s),u = read();
if(s[0]=='M')
{ Tree.modify(u); }
if(s[0]=='Q')
{ printf("%d\n",Tree.query(1,dfn[u])); }
}
return 0;
}
}
signed main()
{ return OMA::main(); }

反思总结:

打暴力不要占用太长时间,不然留给调试可能是正解的代码的时间会不太够,导致出现问题,打完暴力后,也要先把暴力交上,给自己留条后路。

不要去搞极限操作,指在距离考试结束还有7s交代码,rp不好,就会挂掉,是极大概率挂掉。

有想法就要赶快码出来,不要放到最后。

noip29的更多相关文章

  1. 20210803 noip29

    考场 第一次在 hz 考试.害怕会困,但其实还好 看完题感觉不太难,估计有人 AK. T3 比较套路,没办法枚举黑点就从 LCA 处考虑,在一个点变成黑点时计算其他点和它的 LCA 的贡献,暴力跳父亲 ...

随机推荐

  1. R 语言学习过程全记录 ~

    RStudio介绍超详细的教程:https://www.jianshu.com/p/132919ca2ca9 前辈的心得:https://blog.csdn.net/kMD8d5R/article/d ...

  2. python 常见面试问题

    https://blog.csdn.net/weixin_43789195/article/details/87469096 https://blog.csdn.net/qq_42642945/art ...

  3. ESP32-简单OTA升级

    基于ESP-IDF4.1 1 #include "freertos/FreeRTOS.h" 2 #include "freertos/task.h" 3 #in ...

  4. Spring Boot中的那些生命周期和其中的可扩展点(转)

    前言可扩展点的种类Spring Boot启动过程 1.SpringApplication的启动过程 2.ApplicationContext的启动过程 3.一般的非懒加载单例Bean在Spring B ...

  5. Android控件总结

    最常用的控件:TextView.EditText.Button.ImageView TextView                                                文本 ...

  6. linux驱动之获取设备树信息

    上一篇文章学习了字符设备的注册,操作过的小伙伴都知道上一篇文章中测试驱动时是通过手动创建设备节点的,现在开始学习怎么自动挂载设备节点和设备树信息的获取,这篇文章中的源码将会是我以后编写字符驱动的模板. ...

  7. 「AGC010F」 Tree Game

    「AGC010F」 Tree Game 传送门 切了一个 AGC 的题,很有精神. 于是决定纪念一下. 首先如果任意一个人在点 \(u\),他肯定不会向点权大于等于 \(a_u\) 的点走的,因为此时 ...

  8. WIN10小技巧

    WIN10激活: powershell管理员运行slmgr /skms kms.03k.orgslmgr /ato CMD:%TEMP% 全选垃圾,删除 手机投屏到WIN10:win+i---系统-- ...

  9. java02动手动脑

    1 编写一个方法,生成一千个随机数,用ppt提供的纯随机数发生器. 做这个题目时,看到老师已经给出Xn+1=(aXn+c) mod Integer.MAX_VALUE;给出了公式自然就算法明了. 我想 ...

  10. PAT乙级:1083 是否存在相等的差 (20分)

    PAT乙级:1083 是否存在相等的差 (20分) 题干 给定 N 张卡片,正面分别写上 1.2.--.N,然后全部翻面,洗牌,在背面分别写上 1.2.--.N.将每张牌的正反两面数字相减(大减小), ...