\(\color{white}{\mathbb{缀以无尽之群星点点,饰以常青之巨木郁郁,可细斟木纹叶脉,独无可极苍穹之览,名之以:密林}}\)


看完题后感觉整套题都没什么思路,而且基本上整场考试确实是这样

倒序开题,发现 \(t3\) 的做法没有优化空间了,\(t2\) 发现了一些规律,但是卡在求拓扑序上,最后乱搞 \(t1\),本来复杂度及其不正确,但是测的在随机数据下还是很可观的

事实上最后分数比预期高多了


A. 毛一琛

考完 cyh 说才发现是曾经随机跳题跳到的USACO的题,但不幸的是当时直接跳了……

如果直接枚举的话有三种状态:分到第一组,分到第二组,不要,这样是 \(3^n\)

对于这种范围刚刚超的,而且还是枚举集合的题,常常可以使用折半搜索

对于前半段共 \(\frac{n}{2}\) 个元素暴搜一下,消耗 \(3^{\frac{n}{2}}\),并且把每种状态记录在其和的 \(vector\) 里面

右边再重复上述操作,设求出的和为 \(sum\),那么在左边寻找 \(-sum\) 的集合,并且更新和起来的答案即可

代码实现
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=55,maxm=1e6+1e5+5;
  4. int n,a[maxn],half,tot,ans;
  5. bool vis[maxm];
  6. map<int,int>mp;
  7. vector<pair<int,int> >num[maxm];
  8. void dfs1(int pos,int sum,int S1,int S2){
  9. if(pos==half+1){
  10. if(mp.find(sum)==mp.end())mp[sum]=++tot;
  11. num[mp[sum]].push_back(make_pair(S1,S2));
  12. return ;
  13. }
  14. dfs1(pos+1,sum,S1<<1,S2<<1);
  15. dfs1(pos+1,sum+a[pos],S1<<1|1,S2<<1);
  16. dfs1(pos+1,sum-a[pos],S1<<1,S2<<1|1);
  17. return ;
  18. }
  19. void dfs2(int pos,int sum,int S1,int S2){
  20. if(pos==n+1){
  21. if(mp.find(-sum)==mp.end())return ;
  22. int id=mp[-sum];
  23. for(int i=0;i<num[id].size();i++){
  24. // cout<<"hhh";
  25. vis[S1|S2|((num[id][i].first|num[id][i].second)<<(n-half))]=true;
  26. }
  27. return ;
  28. }
  29. dfs2(pos+1,sum,S1<<1,S2<<1);
  30. dfs2(pos+1,sum+a[pos],S1<<1|1,S2<<1);
  31. dfs2(pos+1,sum-a[pos],S1<<1,S2<<1|1);
  32. return ;
  33. }
  34. int main(){
  35. cin>>n;
  36. half=n/2;
  37. // if(n>=10)half+=3;
  38. for(int i=1;i<=n;i++)cin>>a[i];
  39. dfs1(1,0,0,0);
  40. dfs2(half+1,0,0,0);
  41. for(int i=1;i<=(1<<n)-1;i++)if(vis[i])ans++;
  42. cout<<ans;
  43. return 0;
  44. }

B. 毛二琛

考场上想到可以根据先后顺序建边,相当于求有向图的拓扑序个数

然后想到以前有到叫 \(SAO\) 的题,然而当时咕咕咕了……

正解是用 \(dp\) 来做

设 \(f[i][j]\) 表示第 \(i\) 个数在前 \(i\) 个数形成的图中拓扑序为 \(j\) 的方案数

考虑从 \(f[i-1][k]\) 转移

如果 \(i-1\) 向 \(i\) 连边,相当于如果 \(i\) 的拓扑序为 \(j\),那么 \(k\) 的范围为 \([1,j-1]\)

如果 \(i\) 向 \(i-1\) 连边,\(k\) 的范围为 \([j,i]\) (可以取到 \(j\) 是因为加入 \(i\) 这个数相当于把值域往后平移一位,那么原来的 \(j\) 现在相当于 \(j+1\),是满足条件的)

然后发现 \(k\) 的值域是连续的,可以前缀和优化一下

代码实现
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int read(){
  4. int x=0,f=1;
  5. char ch=getchar();
  6. while(!isdigit(ch)){
  7. if(ch=='-')f=-1;
  8. ch=getchar();
  9. }
  10. while(isdigit(ch)){
  11. x=x*10+ch-48;
  12. ch=getchar();
  13. }
  14. return x*f;
  15. }
  16. const int maxn=5005;
  17. const int mod=1e9+7;
  18. int n,a[maxn],f[2][maxn],g[2][maxn],ans;
  19. bool le[maxn];//rk[i]<rk[i+1]
  20. int main(){
  21. n=read();
  22. for(int i=0;i<n;i++)a[i]=read();
  23. for(int i=0;i<n;i++){
  24. if(a[i]<i){//往左走
  25. for(int j=a[i];j<=i-2;j++)le[j]=true;
  26. }
  27. else{
  28. if(i>0)le[i-1]=true;
  29. le[a[i]-1]=true;
  30. }
  31. }
  32. f[0][1]=g[0][1]=1;
  33. for(int i=1;i<=n-2;i++){
  34. for(int j=1;j<=i+1;j++){
  35. if(le[i-1])f[i&1][j]=(g[(i-1)&1][i]-g[(i-1)&1][j-1]+mod)%mod;
  36. else f[i&1][j]=g[(i-1)&1][j-1];
  37. }
  38. for(int j=1;j<=i+1;j++){
  39. g[i&1][j]=(g[i&1][j-1]+f[i&1][j])%mod;
  40. }
  41. }
  42. for(int i=1;i<=n;i++)ans=(ans+f[(n-2)&1][i])%mod;
  43. cout<<ans;
  44. return 0;
  45. }

B. 毛三琛

玄学题

首先应该乖乖地按照题目上说的确定 \(x\)(考场上因为加了个小优化所以不得不先二分再定 \(x\))

当 \(x\) 随机打乱后,最优解的更新序列长度期望是 \(logP\) 的

那么只需要每次开始二分前,\(O(n)\) 判断一下当前 \(x\) 是否比当前答案优即可

代码实现
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=1e5+5;
  4. int n,p,k,a[maxn],ans,b[maxn],x;
  5. int read(){
  6. int x=0,f=1;
  7. char ch=getchar();
  8. while(!isdigit(ch)){
  9. if(ch=='-')f=-1;
  10. ch=getchar();
  11. }
  12. while(isdigit(ch)){
  13. x=x*10+ch-48;
  14. ch=getchar();
  15. }
  16. return x*f;
  17. }
  18. bool check(int limit,int x){
  19. int cnt=1,sum=0;
  20. for(int i=1;i<=n;i++){
  21. int val=(a[i]+x)%p;
  22. if(val>limit) return false;
  23. if(sum+val<=limit)sum+=val;
  24. else sum=val,cnt++;
  25. if(cnt>k)break;
  26. }
  27. if(cnt<=k)return true;
  28. return false;
  29. }
  30. int main(){
  31. srand(time(0));
  32. n=read();
  33. p=read();
  34. k=read();
  35. for(int i=1;i<=n;i++)a[i]=read(),ans+=a[i];
  36. for(int i=0;i<p;i++)b[i]=i;
  37. random_shuffle(b,b+p);
  38. for(int i=0;i<p;i++){
  39. x=b[i];
  40. if(check(ans,x)){
  41. int l=0,r=ans+1;
  42. while(l<r){
  43. int mid=l+r>>1;
  44. if(check(mid,x))r=mid;
  45. else l=mid+1;
  46. }
  47. ans=l;
  48. }
  49. }
  50. cout<<ans;
  51. return 0;
  52. }

\(\color{white}{\mathbb{溯洄从之,道阻且长}}\)

noip模拟30的更多相关文章

  1. noip模拟30[毛毛毛探探探]

    \(noip模拟30\;solutions\) 所以说,这次被初中的大神给爆了????? 其实真的不甘心,这次考场上的遗憾太多,浪费的时间过多,心情非常不好 用这篇题解来结束这场让人伤心的考试吧 \( ...

  2. Noip模拟30 2021.8.4

    T1 毛一琛 考场上打的稳定的$O((2^n)^2)$的暴力.其实再回忆一下上次那道用二进制枚举的题$y$ 就可以知道一样的道理,使用$\textit{Meet In the Middle}$, 按照 ...

  3. 2021.8.4考试总结[NOIP模拟30]

    T1 毛衣衬 将合法子集分为两个和相等的集合. 暴力枚举每个元素是否被选,放在哪种集合,复杂度$O(3^n)$.考虑$\textit{meet in the middle}$. 将全集等分分为两部分分 ...

  4. NOIP模拟 30

    补坑,很多都忘了. T1 树 像我这种人都能考场A掉当然是道水题辣 求出每条有向边的期望就好了 T2 回文串 当时毫无思路,暴力写挂. 首先把B转过来,那么都变成后缀的前缀拼起来 对于每一个LCP,他 ...

  5. NOIP 模拟 $30\; \rm 毛三琛$

    题解 \(by\;zj\varphi\) 二分答案,考虑二分背包中的最大值是多少. 枚举 \(p\) 的值,在当前最优答案不优时,直接跳掉. 随机化一下 \(p\),这样复杂度会有保证. Code # ...

  6. NOIP 模拟 $30\; \rm 毛二琛$

    题解 \(by\;zj\varphi\) 原题问的就是对于一个序列,其中有的数之间有大小关系限制,问有多少种方案. 设 \(dp_{i,j}\) 表示在前 \(i\) 个数中,第 \(i\) 个的排名 ...

  7. NOIP 模拟 $30\; \rm 毛一琛$

    题解 \(by\;zj\varphi\) 如何判断一个集合可以被拆成两个相等的部分? 枚举两个集合,如果它们的和相等,那么他们的并集就是合法的,复杂度 \(\mathcal O\rm(3^n)\) \ ...

  8. 「题解」NOIP模拟测试题解乱写I(29-31)

    NOIP模拟29(B) T1爬山 简单题,赛时找到了$O(1)$查询的规律于是切了. 从倍增LCA那里借鉴了一点东西:先将a.b抬到同一高度,然后再一起往上爬.所用的步数$×2$就是了. 抬升到同一高 ...

  9. noip模拟33

    \(\color{white}{\mathbb{失足而坠千里,翻覆而没百足,名之以:深渊}}\) 这场考试的时间分配非常不科学 开题试图想 \(t1\) 正解,一个半小时后还是只有暴力,特别惊慌失措 ...

随机推荐

  1. vulnhub-XXE靶机

    仅供个人娱乐 靶机信息 靶机下载地址:https://download.vulnhub.com/xxe/XXE.zip 一.主机探测 二.端口服务识别 nmap -sV 192.168.181.149 ...

  2. 图文实例解析,InnoDB 存储引擎中行锁的三种算法

    前文提到,对于 InnoDB 来说,随时都可以加锁(关于加锁的 SQL 语句这里就不说了,忘记的小伙伴可以翻一下上篇文章),但是并非随时都可以解锁.具体来说,InnoDB 采用的是两阶段锁定协议(tw ...

  3. Java8 Lambda表达式(二)

    目录 一.Java8 内置的四大核心函数式接口 1. 消费型接口 Consumer 2. 供给型接口 Supplier 3. 函数型接口 Function 4.断言型接口 Predicate 二.方法 ...

  4. 查看Android 系统发送的广播

    命令行输入如下命令 adb shell dumpsys |grep BroadcastRecord

  5. 『Java』String类使用方法

    Java中的字符串 java.lang.String类表示字符串类,Java程序中所有字符串文字都可以看作实现该类的实例. 特点: 字符串不可变:字符串的值在创建后不能在发生改变 public cla ...

  6. Java集合框架和数组的排序(转载)

    Java集合框架(*Collection)*和数组的排序 ​ 根据约定,在使用java编程的时候应尽可能的使用现有的类库,当然你也可以自己编写一个排序的方法,或者框架,但是有几个人能写得比JDK里的还 ...

  7. docker 安装prometheus和grafna

    一.拉取镜像 docker pull prom/prometheus 二.配置 sudo mkdir /etc/prometheus/ sudo vim /etc/prometheus/prometh ...

  8. DVWA(六):XSS-Reflected 反射型XSS全等级详解

    XSS 概念: 由于web应用程序对用户的输入过滤不严,通过html注入篡改网页,插入恶意脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击. XSS类型: Reflected(反射型):只是简单的 ...

  9. Linux 进程间传递文件描述符

    文章目录 文件描述符 文件数据结构 共享文件 UNIX域socket实现传递文件描述符 进程间传递打开的文件描述符,并不是传递文件描述符的值.先说一下文件描述符. 文件描述符 对内核来说,所有打开的文 ...

  10. metasploit的数据库配置

    metasploit所处位置:/usr/share/metasploit-framework msf数据库连接命令:db_connect msf:msfadmin@127.0.0.1/msf 1.启动 ...