2021.8.4考试总结[NOIP模拟30]
T1 毛衣衬
将合法子集分为两个和相等的集合。
暴力枚举每个元素是否被选,放在哪种集合,复杂度$O(3^n)$。考虑$\textit{meet in the middle}$。
将全集等分分为两部分分别考虑,先$O(3^{\frac{n}{2}})$枚举前一部分的所有情况,记录两个集合的差所对应的状态,然后同样$O(3^{\frac{n}{2}})$枚举后一部分,与前一部分进行匹配即可。
$\textit{meet in the middle}$真还挺神的,以后做题要多考虑。
$code:$

1 #include<bits/stdc++.h>
2 #define int long long
3 #define rin register signed
4 #define pb push_back
5 using namespace std;
6 const int NN=25;
7 int n,m[NN],tot,mx,mid,ans,cnt;
8 bool vis[10000005];
9 map<int,int>tmp;
10 vector<int>sta[10000005];
11 inline int read(){
12 int x=0,f=1; char ch=getchar();
13 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
14 while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
15 return x*f;
16 }
17 inline void write(int x){
18 char ch[20]; int len=0;
19 if(x<0) x=~x+1, putchar('-');
20 do{
21 ch[len++]=x%10+(1<<5)+(1<<4);
22 x/=10;
23 }while(x);
24 for(rin i=len-1;i>=0;--i) putchar(ch[i]);
25 }
26 void ldfs(int s,int ls,int rs,int st){
27 if(s>mid){
28 if(!tmp[ls-rs]) tmp[ls-rs]=++cnt;
29 int now=tmp[ls-rs];
30 sta[now].pb(st);
31 return;
32 }
33 ldfs(s+1,ls,rs,st);
34 ldfs(s+1,ls+m[s],rs,st|(1<<(s-1)));
35 ldfs(s+1,ls,rs+m[s],st|(1<<(s-1)));
36 }
37 void rdfs(int s,int ls,int rs,int st){
38 if(s>n){
39 if(tmp.find(rs-ls)==tmp.end()) return;
40 int now=tmp[rs-ls];
41 for(int i=0;i<sta[now].size();i++){
42 if(st&sta[now][i]) continue;
43 if(!(st|sta[now][i])) continue;
44 if(!vis[st|sta[now][i]]) vis[st|sta[now][i]]=1, ++ans;
45 }
46 return;
47 }
48 rdfs(s+1,ls,rs,st);
49 rdfs(s+1,ls+m[s],rs,st|(1<<(s-1)));
50 rdfs(s+1,ls,rs+m[s],st|(1<<(s-1)));
51 }
52 signed main(){
53 n=read(); tot=(1<<n)-1; mid=n>>1;
54 for(rin i=1;i<=n;i++) m[i]=read();
55 ldfs(1,0,0,0); rdfs(mid+1,0,0,0);
56 write(ans); putchar('\n');
57 return 0;
58 }
T1
T2 猫儿沉
每个位置只能互换一次,那么可以通过当前位置的值与它的位置的大小关系得到一些互换的顺序。
令$pos_i$为元素$a_i$在序列中的位置下标,即$pos_{a_i}=i$,对于序列$s$变为序列$p$的操作顺序,根据大小关系分类讨论:
$pos_i=i$时一定无解,因为这个元素一定要被换到别的地方;
$pos_i<i$时要保证$i$往左移,那么:
为了防止$i$被换到右边,$i-1$位要早于$i$位;
为了使$i$一直被向左换,$i-k$位要早于$i-k-1$位;
为了防止$i$被换到$pos_i$左边,$pos_i-1$位要早于$pos_i$位。
$pos_i>i$时类似。预处理出每个位置的互换顺序,如果过程中有相矛盾的地方,那么无解(数据里没有无解的情况,我懒得没判。
接下来状态转移。定义$f_{i,j}$表示考虑到第$i$个元素,且第$i$个元素在已有序列中拓扑序为$j$的方案数,$tag_i$等于$1$表示第$i-1$位互换早于第$i$位;等于$2$表示第$i$位互换早于第$i-1$位。
于是有应该很好理解的转移方程:
$f_{i,j}=\begin{cases}\sum_{k=1}^{j}f_{i-1,k} & tag_i=1\\\sum_{k=i+1}^{i}f_{i-1,k} & tag_i=2
\end{cases}$
前缀和优化到$O(n^2)$。
$code:$

1 #include<bits/stdc++.h>
2 #define rin register signed
3 using namespace std;
4 const int p=1e9+7,NN=5e3+5;
5 int n,a[NN],tag[NN],pos[NN];//tag==1:i-1在i之前;2:i-1在i之后
6 int f[NN][NN],pre[NN][NN];
7 inline int read(){
8 int x=0,f=1; char ch=getchar();
9 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
10 while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
11 return x*f;
12 }
13 inline void write(int x){
14 char ch[20]; int len=0;
15 if(x<0) x=~x+1, putchar('-');
16 do{
17 ch[len++]=x%10+(1<<5)+(1<<4);
18 x/=10;
19 }while(x);
20 for(int i=len-1;i>=0;--i) putchar(ch[i]);
21 }
22 signed main(){
23 n=read();
24 for(rin i=1;i<=n;i++) a[i]=read()+1, pos[a[i]]=i;
25 for(rin i=1;i<=n;i++){
26 if(pos[i]==i){ puts("0"); return 0; }
27 if(pos[i]<i){
28 tag[i]=1; tag[pos[i]]=1;
29 for(rin j=pos[i]+1;j<i;j++) tag[j]=2;
30 }
31 else{
32 tag[i]=2; tag[pos[i]]=2;
33 for(rin j=i+1;j<a[i];j++) tag[j]=1;
34 }
35 }
36 f[1][1]=pre[1][1]=1;
37 for(rin i=2;i<=n;i++){
38 if(tag[i]==2) for(rin j=1;j<=i;j++) f[i][j]=(pre[i-1][i-1]-pre[i-1][j-1]+p)%p;
39 else for(rin j=1;j<=i;j++) f[i][j]=pre[i-1][j-1]%p;
40 for(rin j=1;j<=i;j++) pre[i][j]=(pre[i][j-1]+f[i][j])%p;
41 }
42 write(pre[n-1][n-1]); putchar('\n');
43 return 0;
44 }
T2
T3 茅散尘
考虑二分。
枚举$x$,在每个$x$下二分背包可以允许的最大容量,最终得到的最小值就是答案。每次check$O(n)$,总复杂度$O(pnlog_{\sum a})$。
显然会T。考虑剪枝。
每次枚举$x$时先$check$一下当前最优答案$ans$,如果连$ans$都不能满足就不用二分,直接跳过即可。在此基础上可以对$x$做一下随机化处理。但我加随机化反而变慢了
$code:$

1 #include<bits/stdc++.h>
2 using namespace std;
3 int p,n,k,a[10005],b[10005];
4 int l,r,ans=INT_MAX;
5 inline int read(){
6 int x=0,f=1; char ch=getchar();
7 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
8 while(ch<='9'&&ch>='0'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
9 return x*f;
10 }
11 inline void write(int x){
12 char ch[20]; int len=0;
13 if(x<0) x=~x+1, putchar('-');
14 do{
15 ch[len++]=x%10+(1<<5)+(1<<4);
16 x/=10;
17 }while(x);
18 for(int i=len-1;i>=0;--i) putchar(ch[i]);
19 }
20 bool check(int mid){
21 int btmp=0,ttmp=0,res;
22 while(btmp<k&&ttmp<n){
23 btmp++; res=0;
24 while(res+b[ttmp+1]<=mid&&ttmp<n) res+=b[++ttmp];
25 }
26 return ttmp==n;
27 }
28 void getmid(int x){
29 int l=0,r=0,res;
30 for(int i=1;i<=n;i++){
31 b[i]=(a[i]+x)%p;
32 r+=b[i]; l=max(l,b[i]);
33 }
34 if(!check(ans)) return;
35 while(l<=r){
36 int mid=l+r>>1;
37 if(check(mid)) r=mid-1, res=mid;
38 else l=mid+1;
39 }
40 ans=min(ans,res);
41 }
42 signed main(){
43 n=read(); p=read(); k=read();
44 for(int i=1;i<=n;i++) a[i]=read();
45 for(int i=0;i<p;i++) getmid(i);
46 write(ans); putchar('\n');
47 return 0;
48 }
T3
原(zhen)始(zheng)题名:T1毛一琛;T2毛二琛;T3毛三琛

《毛 一 琛》
2021.8.4考试总结[NOIP模拟30]的更多相关文章
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- 2021.9.13考试总结[NOIP模拟52]
T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...
- 2021.8.11考试总结[NOIP模拟36]
T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...
- 2021.7.29考试总结[NOIP模拟27]
T1 牛半仙的妹子图 做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数. 我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm ...
- 2021.7.15考试总结[NOIP模拟16]
ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...
- 2021.9.20考试总结[NOIP模拟57]
(换个编辑器代码就SB地不自动折叠了.. T1 2A 考察快读的写法. $code:$ T1 #include<bits/stdc++.h> #define scanf SCANF=sca ...
- 2021.9.14考试总结[NOIP模拟53]
T1 ZYB和售货机 容易发现把每个物品都买成$1$是没有影响的. 然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以 ...
- 2021.9.12考试总结[NOIP模拟51]
T1 茅山道术 仔细观察发现对于每个点只考虑它前面第一个与它颜色相同的点即可. 又仔细观察发现对一段区间染色后以这个区间内点为端点的区间不能染色. 于是对区间右端点而言,区间染色的贡献为遍历到区间左端 ...
- 2021.9.9考试总结[NOIP模拟50]
T1 第零题 神秘结论:从一个点满体力到另一个点的复活次数与倒过来相同. 于是预处理出每个点向上走第$2^i$个死亡点的位置,具体实现可以倍增或二分. 每次询问先从两个点同时向上倍增,都转到离$LCA ...
随机推荐
- WinForm控件常用设置(转)
本来想自己整理一份,但找到了一份挺全的,就直接用到直接找吧 A0 ---- 通用A1 ---- Form 类A2 ---- Control 类A3 ---- MessageBox 类A4 ---- B ...
- TypeScript 中命名空间与模块的理解?区别?
一.模块 TypeScript 与ECMAScript 2015 一样,任何包含顶级 import 或者 export 的文件都被当成一个模块 相反地,如果一个文件不带有顶级的import或者expo ...
- 论文解读(SimCLR)《A Simple Framework for Contrastive Learning of Visual Representations》
1 题目 <A Simple Framework for Contrastive Learning of Visual Representations> 作者: Ting Chen, Si ...
- python 打字小游戏
最近随便用python的pygame编了这个打字小游戏 只要有字母调到窗口底部就结束 上代码: import pygame.freetype import sys import random pyga ...
- 十、Abp vNext 基础篇丨权限
介绍 本章节来把接口的权限加一下 权限配置和使用 官方地址:https://docs.abp.io/en/abp/latest/Authorization 下面这种代码可能我们日常开发都写过,ASP. ...
- javascript,jquery在父窗口触发子窗口(iframe)某按钮的click事件
$('iframe').contents().find(".btn").click(); 其中 contents(): 查找匹配元素内部所有的子节点(包括文本节点).如果元素是一个 ...
- pycharm 增删改查 mysql数据库
1.pycharm创建mysql数据表######################################################import pymysql# 创建连接con = p ...
- [转载]linux上用PHP读取WORD文档
在linux上用PHP读取WORD文档,其实是使用了 antiword程序把word文档转化为txt文档. 再使用php执行系统命令调用而已. 具体操作如下: 1.安装antiword 官方站:htt ...
- 最小化安装centos7心得
在虚拟机里最小化安装了centos7,只有字符界面,发现网卡不通,解决方法: 调整网卡配置文件: cd /etc/sysconfig/network-scripts/ 有两个ifcfg文件,一个ifc ...
- 搞定 NodeJS 开发调试
代码调试有时候是一种充满挑战的工作,如果有一个趁手的调试工具的话,往往可以做到事半功倍的效果.得益于这些年的快速发展,在 NodeJS 生态中已经有了多种调试工具可以使用.我们今年就来分享几个常用的调 ...