T1

一眼看,觉得是个状压,然而又觉得不太行,去打暴力了,然而暴力都打挂的我biss。

正解:

还是暴力,考虑 \(meet \; in \; the \; middle\)

显然对于每个数,只有三种状态,

  1. 不选。
  2. 放入左边集合。
  3. 放入右边集合。

用当前的和,加减当前的数可以表示。

搜索 \([1,mid]\) 时,记录每种 \(sum\) 是选择了那些所组合出来的,0,1表示选还是没选,用 \(bitset\) 来记录状态。

搜索 \([mid+1,n]\) 时,每求出了一个 \(sum\) ,就需要前边那一半出现 \(-sum\) 的方案来得到总的方案数,显然 \(-sum\) 的方案数跟 \(sum\) 的方案数是等价的。

用的 \(unordered\_map\) 里边套了个 \(bitset\),下标是 \(int\) 类型的,表示组合出 \(sum\) 所选的数。

Code
  1. #include<bitset>
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<unordered_map>
  5. #define re register
  6. using std::sort;
  7. using std::bitset;
  8. using std::unordered_map;
  9. const int MAX = 1<<11;
  10. namespace OMA
  11. {
  12. int n,m[21],mid,ans;
  13. bitset<MAX>jud[MAX],tmp;
  14. unordered_map<int,bitset<MAX> >vis;
  15. inline void dfsl(int p,int sum,int opt)
  16. {
  17. if(p==mid+1)
  18. { vis[sum].set(opt); return ; }
  19. dfsl(p+1,sum,opt),dfsl(p+1,sum+m[p],opt|1<<p),dfsl(p+1,sum-m[p],opt|1<<p);
  20. }
  21. inline void dfsr(int p,int sum,int opt)
  22. {
  23. if(p==n+1)
  24. {
  25. if(vis[sum].count())
  26. { tmp = vis[sum]&(~jud[opt]),ans += tmp.count(),jud[opt] |= tmp; }
  27. return ;
  28. }
  29. dfsr(p+1,sum,opt),dfsr(p+1,sum+m[p],opt|(1<<(p-(mid+1)))),dfsr(p+1,sum-m[p],opt|(1<<(p-(mid+1))));
  30. }
  31. signed main()
  32. {
  33. scanf("%d",&n),mid = n/2;
  34. for(re int i=1; i<=n; i++)
  35. { scanf("%d",&m[i]); }
  36. sort(m+1,m+1+n),dfsl(1,0,0),dfsr(mid+1,0,0);
  37. printf("%d\n",ans-1);
  38. return 0;
  39. }
  40. }
  41. signed main()
  42. { return OMA::main(); }

然后发现这份代码在本机编译会CE,因为用了\(unordered\_map\) ,

以下内容摘自oi-wiki,

在 C++11 之前,无序关联式容器属于 C++ 的 TR1 扩展。所以,如果编译器不支持 C++11,在使用时需要在头文件的名称中加入 tr1/ 前缀,并且使用 std::tr1 命名空间。如 #include <unordered_map> 需要改成 #include <tr1/unordered_map>;std::unordered_map 需要改为 std::tr1::unordered_map(如果使用 using namespace std;,则为 tr1::unordered_map)。

但其实直接在终端里开c++11就可以了

T2

\(next_\;permutation\) 可以氵20pts,然而我不会拼 \(permutation\) biss。

正解:

是个dp,考虑排列p中的每个数怎样才能被移动到该到的地方。

这显然是一些相邻的交换的顺序关系,即形如“ \(q\) 中 \(i\) 在 \(i+1\) 前 \(or\) 后”的限制。

问题转化为一个大小为 \(n-1\) 的排列,某些地方限定了相邻两数的大小关系,求方案数。

直接简单DP即可,\(dp_{i,j}\) 表示前i个数,第i个数在前i个数中是第j小的。前缀和优化。

\(O(n^2)\)

Code
  1. 咕咕咕

T3

同样是暴力,有的人a了,有的人wa了。

正解:

暴力

好吧,其实应该算是二分答案,枚举x,计算当前的质量,二分最大值,上界为当前的质量和,判断当前最大值为 \(mid\) 时所分的背包数是否满足 \(\le k\), 同时注意,若当前的质量中有一个大于 \(mid\) ,那显然,当前 \(mid\) 肯定不满足条件,直接break即可。

然后发现,这个T了,只有40pts,考虑如何去优化。

题解说不难发现,二分前,先判断一下是否比当前答案要优,不是直接continue,然后就A了。

至于题解里提到的,随机枚举顺序,好像并没有什么大的作用,或者说,我写假了???QAQ

Code
  1. #include<cstdio>
  2. #include<climits>
  3. #include<algorithm>
  4. #define MAX 10010
  5. #define re register
  6. #define INF INT_MAX
  7. using std::random_shuffle;
  8. namespace OMA
  9. {
  10. inline int read()
  11. {
  12. int s=0,w=1; char ch=getchar();
  13. while(ch<'0'||ch>'9'){ if(ch=='-')w=-1; ch=getchar(); }
  14. while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); }
  15. return s*w;
  16. }
  17. int sum[MAX],ans=INF;
  18. int n,p,k,a[MAX],b[MAX],x[MAX];
  19. inline bool check(int now)
  20. {
  21. int res = 0,cnt = 1;
  22. for(re int i=1; i<=n; i++)
  23. {
  24. if(b[i]>now)
  25. { return false; }
  26. if(res+b[i]>now)
  27. { res = 0,cnt++; }
  28. res += b[i];
  29. }
  30. return cnt<=k;
  31. }
  32. inline int min(int a,int b)
  33. { return a<b?a:b; }
  34. signed main()
  35. {
  36. n = read(),p = read(),k = read();
  37. for(re int i=1; i<=n; i++)
  38. { a[i] = read(); }
  39. for(re int i=0; i<=p-1; i++)
  40. { x[i+1] = i; }
  41. random_shuffle(x+1,x+1+p);
  42. for(re int i=1; i<=p; i++)
  43. {
  44. int res,l = 0,r = 0;
  45. for(re int j=1; j<=n; j++)
  46. { r += (b[j] = (a[j]+x[i])%p); }
  47. if(!check(ans))
  48. { continue ; }
  49. while(l<=r)
  50. {
  51. int mid = (l+r)>>1;
  52. if(check(mid))
  53. { r = mid-1,res = mid; }
  54. else
  55. { l = mid+1; }
  56. }
  57. //printf("res=%d\n",res);
  58. ans = min(ans,res);
  59. }
  60. printf("%d\n",ans);
  61. return 0;
  62. }
  63. }
  64. signed main()
  65. { return OMA::main(); }

反思总结:

  1. 一些STL的东西还是要会的,骗分或者打正解的时候可能会用到,不能不会,比如 \(next\_premutation\) 。

  2. 不能瞧不起暴力,但也不能直接硬怼暴力,万一加个减枝就过了呢。

  3. 注意心态问题,不能自暴自弃。

noip30的更多相关文章

  1. 20210804 noip30

    考场 第一眼感觉 T1 是状压 DP,弃了.T2 好像也是 DP???看上去 T3 比较可做. 倒序开题.T3 暴力是 \(O(pn\log p)\)(枚举 \(x\),二分答案,看能否分成合法的不超 ...

随机推荐

  1. TestComplete 最新安装教程

    在安装TestComplete之前阅读许可协议.通过安装TestComplete,您确认您同意许可的条款和条件. 查看"安装注意事项"部分,确保您的计算机满足硬件和软件要求. 安装 ...

  2. Louvain 论文笔记

    Louvain Introduce Louvain算法是社区发现领域中经典的基于模块度最优化的方法,且是目前市场上最常用的社区发现算法.社区发现旨在发现图结构中存在的类簇(而非传统的向量空间). Al ...

  3. jenkins报错The goal you specified requires a project to execute but there is no POM inthis directory

    报错截图及详细:   15:30:29[ERROR]The goal you specified requires a project to execute but there is no POM i ...

  4. Redis+Lua解决高并发场景抢购秒杀问题

    之前写了一篇PHP+Redis链表解决高并发下商品超卖问题,今天介绍一些如何使用PHP+Redis+Lua解决高并发下商品超卖问题. 为何要使用Lua脚本解决商品超卖的问题呢? Redis在2.6版本 ...

  5. JS高阶函数的使用

    1.何为高阶函数呢? JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数.简单来说,就是对其他 ...

  6. ADB命令 连接WIFI检测序列号

    利用ADB 电脑与手机相连 查看序列号: adb shell  getprop ro.serialno 查看机器的SN号 adb shell getprop 查看机器的全部信息参数 查看IP地址: a ...

  7. Appearance-Based Loop Closure Detection for Online Large-Scale and Long-Term Operation

    Abstract: 本文提出一种用于大规模的长期回环检测,基于一种内存管理方法:限制用于回环检测的位置数目,以满足实时性要求. introduction: 大场景存在的最关键问题:随着场景增大,回环检 ...

  8. 【LeetCode】66. 加一

    66. 加一 知识点:数组: 题目描述 给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储单个数字. 你可以假设除了整数 0 ...

  9. python基础之列表推导式

    #列表推导式 ---> 返回的是列表 for语句 效率更高# 1*1 2*2 3*3 4*4 5*5 6*6 7*7 8*8 9*9# import time# to = time.clock( ...

  10. python 连接远程服务器,修改时间

    import paramiko from datetime import date, timedelta def set_time(hostname): ssh = paramiko.SSHClien ...