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毛三琛

《毛 一 琛》

最新文章

  1. 对于System.Net.Http的学习(一)——System.Net.Http 简介
  2. Vmware vsphere webservice sdk 连接打开慢的问题
  3. [ 学习路线 ] 2015 前端(JS)工程师必知必会 (2)
  4. [ACM_水题] UVA 11729 Commando War [不可同时交代任务 可同时执行 最短完成全部时间 贪心]
  5. Photoshop操作指南
  6. hardware control language
  7. 算法系列1《DES》
  8. eclipse简单注释规范
  9. MVC架构学习
  10. 根据SimpleScheduleBuilder配置不同的SimpleTrigger触发器
  11. mailsend - Send mail via SMTP protocol from command line
  12. C#中byte[] 与指针
  13. LeetCode OJ 66. Plus One
  14. trie 树 模板
  15. MinerQueue.java 访问队列
  16. 环境判断:区别h5打开还是weixin打开?
  17. Python dict 将元祖转成字典
  18. Pushlets 配置参数详解
  19. 第三章基本的SQl查询语言
  20. [ 原创 ] Java基础6--构造函数和抽象类的性质

热门文章

  1. window 日志的查看与清理
  2. Tomcat部署与优化
  3. 【PHP数据结构】图的概念和存储结构
  4. js判断访客来源网址和关键字
  5. mongodb linux基本启动 基础增删改 mysql语法的对比
  6. web、app、小程序测试异同点
  7. javascript 字符串 数字反转 字母大小写互换
  8. [转载]CentOS 7 创建本地YUM源
  9. mqtt网关服务器连接阿里云关联物模型
  10. .Net Core 实现 自定义Http的Range输出实现断点续传或者分段下载