5.23考试总结(NOIP模拟2)
5.23考试总结(NOIP模拟2)
洛谷题单
看第一题第一眼,不好打呀;看第一题样例又一眼,诶,我直接一手小阶乘走人
然后就急忙去干T2T3了
后来考完一看,只有\(T1\)骗到了\(15pts\)[尴尬\(.jpg\)]
\(T1\)P3322 [SDOI2015]排序
背景
说实话,看见这题正解是dfs的那一刻,我人都傻了[流泪.jpg]
在讲这题的时候赵队@yspm 类比了线段树的思想%%%%%,在食用本篇题解时可以想一下
解题思路
最基本的一个思想:结果与操作的顺序无关,因为在更换的时候无论先换哪一个最后排列都是一定的。
因此我们肯定会用到\(A_n^n\)也就是n的阶乘,需要初始化一下,这里用的jc数组记录
然后就可以 愉快 搜索了。
先是check函数;
check(x)用来检查所有长度为1<<x的块是否满足递增,
有一个非常妙的地方:我们已经知道这个序列是由1~\(2^n\)组成的了因此在判断的时候只需要循环,看第i块的第一个数是否和第j块的第一个数正好差一个块长就好了
bool check(int x)
{
for(int i=1;i<=(1<<(n-x));i++)
if(s[(i-1)*(1<<x)+1]+(1<<(x-1))!=s[(i-1)*(1<<x)+(1<<(x-1))+1])
return false;
return true;
}
再谈交换函数:
swap(i,j,k)表示将分别以i和j开始长度为k的序列互换void swap(int i,int j,int k)
{
for(int l=1;l<=k;l++)
swap(s[i+l-1],s[j+l-1]);
}
最后是dfs函数
dfs(x,num)表示交换到块长为1<<x了,并且此前进行了num个操作
如果这个块不是单调递增的,直接return就好,毕竟他对于答案是没有贡献的
对于x==n时表明整个序列已经整完了,然后直接给ans加上jc[num]就好了
然后直接向下进行dfs(x+1,num)不做任何处理
对于进行处理的情况,把整个序列两块两块的看,如果不符合条件(判断方法与上面的check同)记录到一个t数组里,一会处理,
如果需要处理的总数超过4的话直接break,剩下的直接交给后面就可以了然后暴力两两枚举操作,进行交换后,直接进行下一层dfs以及回溯就好了
\(code\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e3;
int n,ans,jc[13],s[N];
bool check(int x)
{
for(int i=1;i<=(1<<(n-x));i++)
if(s[(i-1)*(1<<x)+1]+(1<<(x-1))!=s[(i-1)*(1<<x)+(1<<(x-1))+1])
return false;
return true;
}
void swap(int i,int j,int k)
{
for(int l=1;l<=k;l++)
swap(s[i+l-1],s[j+l-1]);
}
void dfs(int x,int num)
{
if(x&&!check(x))
return ;
if(x==n)
{
ans+=jc[num];
return ;
}
dfs(x+1,num);
int t[5],tot=0;
for(int i=1;i<=(1<<(n-x));i+=2)
if(s[i*(1<<x)+1]!=s[(i-1)*(1<<x)+1]+(1<<x))
{
if(tot==4)
break;
t[++tot]=i;
t[++tot]=i+1;
}
if(!tot)
return ;
for(int i=1;i<=tot;i++)
for(int j=i+1;j<=tot;j++)
{
swap((1<<x)*(t[i]-1)+1,(1<<x)*(t[j]-1)+1,1<<x);
dfs(x+1,num+1);
swap((1<<x)*(t[i]-1)+1,(1<<x)*(t[j]-1)+1,1<<x);
}
}
#undef int
int main()
{
#define int long long
scanf("%lld",&n);
jc[0]=1;
for(int i=1;i<=n;i++)
jc[i]=jc[i-1]*i;
for(int i=1;i<=(1<<n);i++)
scanf("%lld",&s[i]);
dfs(0,0);
printf("%lld",ans);
return 0;
}
\(T2\)题解 P3643 [APIO2016]划艇
背景
打了挺长时间爆搜,考完一交到洛谷,TLE是小事,重点是运行了3.73min,难怪一分没有QAQ
解题思路
先想一下最简单的打法吧
用f[i][j]表示前i所学校中,第i所学校参赛,且派出j艘划艇的方案数
显然,\(f[i][j]=1+∑_{k=1}^{i-1}∑_{k=1}^{j-1}f[k][t]\)
考虑优化,我们需要的只是长度,因此可以将每个端点离散化,然后分段枚举
方案分两部分:
- i从(j-1)~j选一个,前面所有的学校要么不选要么从1~(j-1)区间中选,方案数为\(\sum\limits_{l=1}^{i-1}\sum\limits_{r=1}^{j-1} f[l][r]*C_{len}^1\)
- i从(j-1)j选一个,前面有学校也从(j-1)j中选,定第一个从(j-1)j中选的学校为k,显然总方案数为(ki的方案数)*\(\sum\limits_{l=1}^{k-1}\sum\limits_{r=1}^{j-1} f[l][r]\)
将1和2式子合并一下就可以得到\(\sum\limits_{l=1}^{i-1}\sum\limits_{r=1}^{j-1} f[l][r]+\sum\limits_{l=1}^{k-1}\sum\limits_{r=1}^{j-1} f[l][r]\)
可知ki学校一定选择j-1j中的数或者选择0,
因为k和i都从j区间中选,k+1~i-1学校可以选择j区间的如果选的话一定从j区间中选,如果不选就选0,而不可以选j区间的一定不能派划艇
有一个引理
从区间[0,L]中取n个数,要求所有非零数严格递增,则方案数为\(C_n^{L+n}\)
一看这式子,直接杨辉三角走起,再一看数据范围。。。。十分不友善,考虑一下从以前的状态中转移过来:
\(C_{n+1}^{m+1}=C_n^m*\frac{n+1}{m+1}\)
然后用前缀和维护一下
f[i][j],表示1~i学校从1~j区间选的方案总数,也就是下面的式子:
\(f[i][j]=len*f[i-1][j-1]+\sum\limits_{k=i-1}^{1} C_{l+p-2}^p*f[k-1][j-1]\)
\(code\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e2+10,mod=1e9+7;
int n,cnt,ans,ys[N<<1],a[N],b[N],f[N],g[N],inv[N];
void get_INV()
{
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++)
inv[i]=((mod-mod/i)*inv[mod%i])%mod;
}
#undef int
int main()
{
#define int long long
scanf("%lld",&n);
get_INV();
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i],&b[i]);
ys[++cnt]=a[i];
ys[++cnt]=++b[i];
}
sort(ys+1,ys+cnt+1);
cnt=unique(ys+1,ys+cnt+1)-ys-1;
for(int i=1;i<=n;i++)
{
a[i]=lower_bound(ys+1,ys+cnt+1,a[i])-ys;
b[i]=lower_bound(ys+1,ys+cnt+1,b[i])-ys;
}
f[0]=g[0]=1;
for(int j=1;j<cnt;j++)
{
int len=ys[j+1]-ys[j];
for(int i=1;i<=n;i++)
g[i]=g[i-1]*(len+i-1)%mod*inv[i]%mod;
for(int i=n;i>=1;i--)
if(a[i]<=j&&j<b[i])
for(int k=i-1,tot=1;k>=0;k--)
{
f[i]=(f[i]+f[k]*g[tot]%mod)%mod;
if(a[k]<=j&&j<b[k])
tot++;
}
}
for(int i=1;i<=n;i++)
ans=(ans+f[i])%mod;
printf("%lld",ans);
return 0;
}
\(T3\)题解 P3158 [CQOI2011]放棋子
背景
考试的时候这个题也看了不短时间,想到了题解的一小部分,剩下的就不知道偏到哪去了,本来一开始还想整一下dp呢,到了后来直接组合数学呀,欧拉筛呀一些玄学东西,最后的测试结果也是WA,RE,TLE五花八门的。。。
解题思路
首先感谢这篇blog,以及赵队的讲解,让我懂了这个题。。。
因为n的数据比较小吗,我们的数组可以多开那么两维
f[i][j][k]表示前k种颜色占领了任意i行j列的方案数。
g[i][j][k]表示任意k枚同色棋子放任意i行j列的方案数。
g数组主要用于维护f数组
先看f数组
\(f[i][j][k]=\sum_{l=0}^{i-1}\sum_{r=0}^{j-1}f[l][r][k-1]*g[i-l][j-r][s[k]]*C^{n-l}_{i-l}*C^{m-r}_{j-r}\)
更新的条件是$(i-l)*(j-r) \ge s[k] $
\(\sum_{l=0}^{i-1}\sum_{r=0}^{j-1}\)枚举前k-1种颜色在l行r列时的情况
\(f[l][r][k-1]\)为前k-1种颜色在l行r列时的方案数
\(g[i-l][j-r][s[k]]*C^{n-l}_{i-l}*C^{m-r}_{j-r}\)则是枚举第k种颜色在i-l行j-r列的方案数
再看g数组
\(g[i][j][k]=C^{i*j}_k-\sum_{l=1}^i\sum_{r=1}^jg[l][r][k]*C_l^i*C_r^j\)
更新的条件是\(l<i||r<j\)并且\(i*j \ge k\)
\(C^{i*j}_k\)就是把i*j个数中整出来k个
由于我们要求g[i][j][k]要求记录的是把前i行前j列占满的情况,这里需要容斥一下
\(\sum_{l=1}^i\sum_{r=1}^jg[l][r][k]*C_l^i*C_r^j\)表示前i行前j列没有占满,也就是不符合条件的方案数
一些优化
显而易见,我们在求组合数时可以用杨辉三角预处理一下。
并且通过观察我们发现g数组通过在枚举种数是可以压掉最后一维节省空间。
在运算的时候要多取mod,杨辉三角求组合数尽量初始化大一些,否则连样例都过不了(别问我为什么知道,我就是知道[流泪.jpg])
code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=35,M=310,mod=1e9+9;
int n,m,t,ans,s[N],c[N*N][N*N],f[N][N][N],g[N][N];
void get_C()
{
for(int i=0;i<N*N;i++)
{
c[i][0]=1;
for(int j=1;j<=i;j++)
c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
#undef int
int main()
{
#define int long long
scanf("%lld%lld%lld",&n,&m,&t);
f[0][0][0]=1;
get_C();
for(int k=1;k<=t;k++)
{
scanf("%lld",&s[k]);
memset(g,0,sizeof(g));
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i*j>=s[k])
g[i][j]=c[i*j][s[k]];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(i*j>=s[k])
for(int l=1;l<=i;l++)
for(int r=1;r<=j;r++)
if(l<i||r<j)
g[i][j]=(g[i][j]-g[l][r]*c[i][l]%mod*c[j][r]%mod+mod)%mod;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int l=0;l<i;l++)
for(int r=0;r<j;r++)
if((i-l)*(j-r)>=s[k])
f[i][j][k]=(f[i][j][k]+f[l][r][k-1]*g[i-l][j-r]%mod*c[n-l][i-l]%mod*c[m-r][j-r]%mod)%mod;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
ans=(ans+f[i][j][t])%mod;
printf("%lld",ans%mod);
return 0;
}
5.23考试总结(NOIP模拟2)的更多相关文章
- 8.23考试总结(NOIP模拟46)[数数·数树·鼠树·ckw的树]
T1 数数 解题思路 大概是一个签到题的感觉...(但是 pyt 并没有签上) 第一题当然可以找规律,但是咱们还是老老实实搞正解吧... 先从小到大拍个序,这样可以保证 \(a_l<a_r\) ...
- 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]
6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...
- 5.22考试总结(NOIP模拟1)
5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...
- [考试总结]noip模拟23
因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...
- 2021.9.17考试总结[NOIP模拟55]
有的考试表面上自称NOIP模拟,背地里却是绍兴一中NOI模拟 吓得我直接文件打错 T1 Skip 设状态$f_i$为最后一次选$i$在$i$时的最优解.有$f_i=max_{j<i}[f_j+a ...
- 「考试」noip模拟9,11,13
9.1 辣鸡 可以把答案分成 每个矩形内部连线 和 矩形之间的连线 两部分 前半部分即为\(2(w-1)(h-1)\),后半部分可以模拟求(就是讨论四种相邻的情况) 如果\(n^2\)选择暴力模拟是有 ...
- 6.11考试总结(NOIP模拟7)
背景 时间分配与得分成反比,T1 20min 73pts,T2 1h 30pts,T3 2h 15pts(没有更新tot值,本来应该是40pts的,算是本次考试中最遗憾的地方了吧),改起来就是T3比较 ...
- 6.10考试总结(NOIP模拟6)
前言 就这题考的不咋样果然还挺难改的.. T1 辣鸡 前言 我做梦都没想到这题正解是模拟,打模拟赛的时候看错题面以为是\(n\times n\)的矩阵,喜提0pts. 解题思路 氢键的数量计算起来无非 ...
- 6.7考试总结(NOIP模拟5)
前言 昨天说好不考试来着,昨晚就晚睡颓了一会,今天遭报应了,也没好好考,考得挺烂的就不多说了. T1 string 解题思路 比赛上第一想法就是打一发sort,直接暴力,然后完美TLE40pts,这一 ...
随机推荐
- flex布局的使用
一.Flex布局是什么? Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为Flex布局. .box{ disp ...
- Windows反调试技术(下)
OD的DBGHELP模块 检测DBGHELP模块,此模块是用来加载调试符号的,所以一般加载此模块的进程的进程就是调试器.绕过方法也很简单,将DBGHELP.DLL改名. #include <Wi ...
- 测试中常用的链接URL----方便自己查找
1.TesterHome:https://testerhome.com/ 2.selenium的操作手册:https://selenium-python.readthedocs.io/ 3.
- 3. java基础语法
3.1 注释(理解) 注释是对代码的解释和说明文字,可以提高程序的可读性,因此在程序中添加必要的注释文字十分重要.Java中的 注释分为三种: 单行注释.单行注释的格式是使用//,从//开始至本行结尾 ...
- [刷题] 46 Permutations
要求 整型数组,每个元素不相同,返回元素所有排列的可能 示例 [1,2,3] [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 思路 树 ...
- centOS 7 安装 CUPS 打印服务器,安装映美 FP-730K打印机共享
centOS 7 安装 CUPS 打印服务器,安装映美 FP-730K打印机共享 2017-09-13 16:27:02 mostone 阅读数 3698 版权声明:本文为博主原创文章,遵循CC ...
- Windows10查看电脑的USB接口是2.0还是3.0
Windows10查看电脑的USB接口是2.0还是3.0原创小晓酱手记 最后发布于2019-08-22 16:09:48 阅读数 3662 收藏展开 同事要拷贝资料给我,问我电脑的USB接口是2.0还 ...
- Prometheus 通过 consul 实现自动服务发现
1.Consul 介绍 Consul 是基于 GO 语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册.服务发现和配置管理的功能.Consul 提供服务注册/发现.健康检查.Key/Valu ...
- 11.8 iotop:动态显示磁盘I/O统计信息
iotop命令是一款实时监控磁盘I/O的工具,但必须以root用户的身份运行.使用iotop命令可以很方便地查看每个进程使用磁盘I/O的情况. 最小化安装系统一般是没有这个命令的,需要使用yum命令额 ...
- git/repo常用命令
Git作为广受欢迎的一款版本控制工具,它该如何通过命令行使用呢?本文为你揭晓浓缩精华精华版:git常用命令一览,含部分repo操作. 代码下载 repo init -- -->初始化需要下载的分 ...