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]的更多相关文章

  1. 2021.9.17考试总结[NOIP模拟55]

    有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...

  2. 2021.9.13考试总结[NOIP模拟52]

    T1 路径 考虑每一位的贡献,第$i$位每$2^i$个数会变一次,那么答案为$\sum_{i=1}^{log_2n} \frac{n}{2^i}$. $code:$ 1 #include<bit ...

  3. 2021.8.11考试总结[NOIP模拟36]

    T1 Dove玩扑克 考场并查集加树状数组加桶期望$65pts$实际$80pts$,考后多开个数组记哪些数出现过,只扫出现过的数就切了.用$set$维护可以把被删没的数去掉,更快. $code:$ 1 ...

  4. 2021.7.29考试总结[NOIP模拟27]

    T1 牛半仙的妹子图 做法挺多的,可以最小生成树或者最短路,复杂度O(cq),c是颜色数. 我考场上想到了原来做过的一道题影子,就用了并查集,把边权排序后一个个插入,记录权值的前缀和,复杂度mlogm ...

  5. 2021.7.15考试总结[NOIP模拟16]

    ZJ模拟D2就是NB.. T1 Star Way To Heaven 谁能想到这竟是个最小生成树呢?(T1挂分100的高人JYF就在我身边 把上边界和下边界看成一个点和星星跑最小生成树,从上边界开始跑 ...

  6. 2021.9.20考试总结[NOIP模拟57]

    (换个编辑器代码就SB地不自动折叠了.. T1 2A 考察快读的写法. $code:$ T1 #include<bits/stdc++.h> #define scanf SCANF=sca ...

  7. 2021.9.14考试总结[NOIP模拟53]

    T1 ZYB和售货机 容易发现把每个物品都买成$1$是没有影响的. 然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以 ...

  8. 2021.9.12考试总结[NOIP模拟51]

    T1 茅山道术 仔细观察发现对于每个点只考虑它前面第一个与它颜色相同的点即可. 又仔细观察发现对一段区间染色后以这个区间内点为端点的区间不能染色. 于是对区间右端点而言,区间染色的贡献为遍历到区间左端 ...

  9. 2021.9.9考试总结[NOIP模拟50]

    T1 第零题 神秘结论:从一个点满体力到另一个点的复活次数与倒过来相同. 于是预处理出每个点向上走第$2^i$个死亡点的位置,具体实现可以倍增或二分. 每次询问先从两个点同时向上倍增,都转到离$LCA ...

随机推荐

  1. CSS001. 纯CSS实现瀑布流(纵向排序)

    通过 Multi-columns 相关的属性 column-count.column-gap 配合 break-inside 来实现瀑布流布局. 首先对包裹图片的盒子增加样式,column-count ...

  2. 理解ASP.NET Core - [04] Host

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 本文会涉及部分 Host 相关的源码,并会附上 github 源码地址,不过为了降低篇幅,我会 ...

  3. .net Core 基于EF Core 实现数据库上下文

    在做项目时,需要将某一些功能的实体建立在另一个数据库中,连接不同的数据库用以存储记录.通过查找资料,实现EF Core上下文. 下面是实现上下文后的解决方案的目录: 1.UpAndDownDbCont ...

  4. Nginx系列(2)- 正向代理和反向代理

    Nginx作用 Http代理,反向代理:作为web服务器最常用的功能之一,尤其是反向代理 正向代理是代理客户端,反向代理是代理服务端 正向代理要知道访问服务器的地址,反向代理不需要知道访问服务器的真实 ...

  5. Ubuntu18.04安装jenkins

    官网参考指引:https://pkg.jenkins.io/debian-stable/ wget -q -O - https://pkg.jenkins.io/debian-stable/jenki ...

  6. python学习笔记(一)-基础知识

    O.解释型语言和编译型语言 编译型语言就是先把写好的程序翻译成计算机语言然后执行,就是所谓的一次编译到处运行,比如c.c++就是编译型语言,这样的语言特点是运行速度快,但是需要事先把程序编译好才可以. ...

  7. jmeter旅程第二站:jmeter登录接口测试

    因为上一篇已经讲了jmeter抓包,那么接下来会将讲解jmeter接口测试. 这里以浏览器为例. 从简到繁,那么首先先以比较常见的登录做实例. 目前登录操作有这几种:账户是否存在.账户密码登录.验证码 ...

  8. whistle安装

    可参考官方帮助文档:https://wproxy.org/whistle/install.html 系统:windows10   jdk:1.8.0_171    node:10.16.0    np ...

  9. WPF进阶技巧和实战06-控件模板

    逻辑树和可视化树 System.Windows.LogicalTreeHelper System.Windows.Media.VisualTreeHelper 逻辑树类(LogicalTreeHelp ...

  10. Gaussion

    # Kernel density estimation import numpy as np import matplotlib.pyplot as plt from scipy.stats impo ...