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
  1. #include<cstdio>
  2. #define MAX 1000010
  3. #define re register
  4. namespace OMA
  5. {
  6. long long n,ans;
  7. int t,a,b,c,d,m,len,xam;
  8. int tmp[MAX],pos[MAX];
  9. inline int max(int a,int b)
  10. { return a>b?a:b; }
  11. class BIT
  12. {
  13. private:
  14. int tree[MAX];
  15. inline int lowbit(int x)
  16. { return x&-x; }
  17. public:
  18. inline void insert(int x,int lis)
  19. {
  20. for(re int i=x; i<=xam; i+=lowbit(i))
  21. { tree[i] = max(tree[i],lis); }
  22. }
  23. inline int query(int x)
  24. {
  25. int res = 0;
  26. for(re int i=x; i; i-=lowbit(i))
  27. { res = max(res,tree[i]); }
  28. return res;
  29. }
  30. }BIT;
  31. signed main()
  32. {
  33. scanf("%lld%d%d%d%d%d",&n,&t,&a,&b,&c,&d);
  34. if(n==1)
  35. { printf("1\n"); return 0; }
  36. tmp[1] = t;
  37. for(re int i=2; i<=n; i++)
  38. {
  39. xam = max(xam,tmp[i] = (a*tmp[i-1]*tmp[i-1]+b*tmp[i-1]+c)%d);
  40. if(pos[tmp[i]])
  41. { len = i-pos[tmp[i]],m = i-1; break ; }
  42. pos[tmp[i]] = i;
  43. }
  44. xam += 1;
  45. ans = (n-m)/len-150,n = (n-m)%len+len*150+m;
  46. for(re int i=m+1; i<=n; i++)
  47. { tmp[i] = tmp[pos[tmp[m+1]]+i-m-1]; }
  48. int lis = 0;
  49. for(re int i=1; i<=n; i++)
  50. {
  51. tmp[i] += 1;
  52. int res = BIT.query(tmp[i])+1;
  53. BIT.insert(tmp[i],res);
  54. lis = max(lis,res);
  55. }
  56. printf("%lld\n",ans+lis);
  57. return 0;
  58. }
  59. }
  60. signed main()
  61. { return OMA::main(); }

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

矩阵快速幂解法

T2

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

别人的想法:

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

正解:

%%%沈学长。

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

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

Code
  1. 咕咕咕

T3

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

正解:

就是个线段树。

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

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

Code
  1. #include<cstdio>
  2. #include<cstring>
  3. #include<climits>
  4. #define MAX 100010
  5. #define re register
  6. #define INF INT_MIN
  7. int n,m;
  8. int w[MAX];
  9. bool vis[MAX];
  10. struct graph
  11. {
  12. int next;
  13. int to;
  14. }edge[MAX<<1];
  15. int cnt=1,head[MAX];
  16. inline void add(int u,int v)
  17. { edge[++cnt] = (graph){head[u],v},head[u] = cnt; }
  18. namespace FTC
  19. {
  20. int fa[MAX],size[MAX],dfn[MAX];
  21. inline void dfs(int u,int fat)
  22. {
  23. size[u] = 1,dfn[u] = ++cnt,fa[u] = fat;
  24. for(re int i=head[u],v; i; i=edge[i].next)
  25. {
  26. v = edge[i].to;
  27. if(v!=fat)
  28. { dfs(v,u); size[u] += size[v]; }
  29. }
  30. }
  31. }using namespace FTC;
  32. namespace OMA
  33. {
  34. inline int max(int a,int b)
  35. { return a>b?a:b; }
  36. class Segment_Tree
  37. {
  38. private:
  39. struct TREE
  40. {
  41. int xam;
  42. int l,r;
  43. int tag;
  44. TREE()
  45. { xam = -1; }
  46. }st[MAX<<2];
  47. inline int ls(int p)
  48. { return p<<1; }
  49. inline int rs(int p)
  50. { return p<<1|1; }
  51. inline void Push_up(int p)
  52. { st[p].xam = max(st[ls(p)].xam,st[rs(p)].xam); }
  53. inline void Push_down(int p)
  54. {
  55. if(st[p].tag)
  56. {
  57. st[ls(p)].xam = max(st[ls(p)].xam,st[p].tag);
  58. st[ls(p)].tag = max(st[ls(p)].tag,st[p].tag);
  59. st[rs(p)].xam = max(st[rs(p)].xam,st[p].tag);
  60. st[rs(p)].tag = max(st[rs(p)].tag,st[p].tag);
  61. st[p].tag = 0;
  62. }
  63. }
  64. public:
  65. inline void build(int p,int l,int r)
  66. {
  67. st[p].l = l,st[p].r = r;
  68. if(l==r)
  69. { return ; }
  70. int mid = (l+r)>>1;
  71. build(ls(p),l,mid),build(rs(p),mid+1,r);
  72. }
  73. inline void update(int p,int l,int r,int val)
  74. {
  75. if(l>r)
  76. { return ; }
  77. if(l<=st[p].l&&st[p].r<=r)
  78. { st[p].xam = max(st[p].xam,val); st[p].tag = max(st[p].tag,val); return ; }
  79. Push_down(p);
  80. int mid = (st[p].l+st[p].r)>>1;
  81. if(l<=mid)
  82. { update(ls(p),l,r,val); }
  83. if(r>mid)
  84. { update(rs(p),l,r,val); }
  85. Push_up(p);
  86. }
  87. inline int query(int p,int pos)
  88. {
  89. if(st[p].l==st[p].r)
  90. { return st[p].xam; }
  91. Push_down(p);
  92. int ans = INF,mid = (st[p].l+st[p].r)>>1;
  93. if(pos<=mid)
  94. { ans = max(ans,query(ls(p),pos)); }
  95. else
  96. { ans = max(ans,query(rs(p),pos)); }
  97. return ans;
  98. }
  99. inline void modify(int u)
  100. {
  101. update(1,dfn[u],dfn[u]+size[u]-1,w[u]);
  102. while(!vis[u]&&fa[u])
  103. {
  104. vis[u] = 1;
  105. update(1,dfn[fa[u]],dfn[u]-1,w[fa[u]]);
  106. update(1,dfn[u]+size[u],dfn[fa[u]]+size[fa[u]]-1,w[fa[u]]);
  107. u = fa[u];
  108. }
  109. }
  110. }Tree;
  111. inline int read()
  112. {
  113. int s=0,w=1; char ch=getchar();
  114. while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
  115. while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
  116. return s*w;
  117. }
  118. signed main()
  119. {
  120. n = read(),m = read();
  121. for(re int i=1; i<=n; i++)
  122. { w[i] = read(); }
  123. for(re int i=1,u,v; i<=n-1; i++)
  124. { u = read(),v = read(); add(u,v),add(v,u); }
  125. cnt = 0,dfs(1,0);
  126. Tree.build(1,1,n);
  127. for(re int i=1,u; i<=m; i++)
  128. {
  129. char s[10]; scanf("%s",s),u = read();
  130. if(s[0]=='M')
  131. { Tree.modify(u); }
  132. if(s[0]=='Q')
  133. { printf("%d\n",Tree.query(1,dfn[u])); }
  134. }
  135. return 0;
  136. }
  137. }
  138. signed main()
  139. { return OMA::main(); }

反思总结:

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

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

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

noip29的更多相关文章

  1. 20210803 noip29

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

随机推荐

  1. 滑动窗口通用解leetcode字符串匹配问题

    滑动窗口,这玩意解决一些字符串匹配的题目是真的挺好用的,虽然本质还是双指针. 思路: 1.维护一个窗口,不断的向右边移动 2.满足要求后,移动左边,当不满足时,跳出. 3.重复1,2.得出答案. 下面 ...

  2. IBM刀箱服务器的SW

    刀箱交换机说明: 1.刀箱交换机可以看到的24个口都是ext端口,其中因为授权原因,只激活了前10个端口. 2.交换机配置中的inta端口为服务器直接连接的端口,inta1-inta14,这些都是对应 ...

  3. NOIP 模拟赛 day5 T2 水 故事题解

    题目描述 有一块矩形土地被划分成 \(\small n×m\) 个正方形小块.这些小块高低不平,每一小块都有自己的高度.水流可以由任意一块地流向周围四个方向的四块地中,但是不能直接流入对角相连的小块中 ...

  4. .h .cpp区别

    首先,我们可以将所有东西都放在一个.cpp文件内. 然后编译器就将这个.cpp编译成.obj,obj是什么东西? 就是编译单元了.一个程序,可以由一个编译单元组成, 也可以有多个编译单元组成. 如果你 ...

  5. C语言:char总结

    char字符型数据1.用单引号限制的1字节的字符称为字符型数据,字符型常量2.字符型常量实质保存的是对应字符的ASCII码值,是一个整数3.字符型常量表示范围:0-2554.声明字符型变量 char ...

  6. Java基础00-循环语句7

    1. for循环语句 1.1 循环结构 1.2 for循环语句的格式 执行流程图: 1.3 案例 (1)输出数据 (2)求和 (3)求偶数和 (4)水仙花 public static void mai ...

  7. Java 批量删除Word中的空白段落

    1. 测试文档.期望达到的目标文档效果 用于测试的Word文档如下所示,包含的空白段落影响文章整体布局及美观性: 目标文档效果: 2. 辅助工具 2.1 使用类库:Free Spire.Doc for ...

  8. 将py文件打包成exe文件

    PyInstaller工具是跨平台的,它既可以在 Windows平台上使用,也可以在 Mac OS X 平台上运行.在不同的平台上使用 PyInstaller 工具的方法是一样的,它们支持的选项也是一 ...

  9. js学习笔记之this指向及形参实参

    var length = 10 function fn () { console.log(this.length) } var obj = { length: 5, method (fn) { fn( ...

  10. 《Android原生整合虹软SDK开发uniapp插件》

    1.项目背景 应公司要求,需要开发一套类似人脸打卡功能的app,但是因为我们公司没有很强的原生android开发者,所以根据现状选择了第三方跨平台的uniapp,想必目前大多人都了解这个平台了,我也就 ...