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]\)

考虑优化,我们需要的只是长度,因此可以将每个端点离散化,然后分段枚举

方案分两部分:

  1. 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\)
  2. 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)的更多相关文章

  1. 8.23考试总结(NOIP模拟46)[数数·数树·鼠树·ckw的树]

    T1 数数 解题思路 大概是一个签到题的感觉...(但是 pyt 并没有签上) 第一题当然可以找规律,但是咱们还是老老实实搞正解吧... 先从小到大拍个序,这样可以保证 \(a_l<a_r\) ...

  2. 6.17考试总结(NOIP模拟8)[星际旅行·砍树·超级树·求和]

    6.17考试总结(NOIP模拟8) 背景 考得不咋样,有一个非常遗憾的地方:最后一题少取膜了,\(100pts->40pts\),改了这么多年的错还是头一回看见以下的情景... T1星际旅行 前 ...

  3. 5.22考试总结(NOIP模拟1)

    5.22考试总结(NOIP模拟1) 改题记录 T1 序列 题解 暴力思路很好想,分数也很好想\(QAQ\) (反正我只拿了5pts) 正解的话: 先用欧拉筛把1-n的素数筛出来 void get_Pr ...

  4. [考试总结]noip模拟23

    因为考试过多,所以学校的博客就暂时咕掉了,放到家里来写 不过话说,vscode的markdown编辑器还是真的很好用 先把 \(noip\) 模拟 \(23\) 的总结写了吧.. 俗话说:" ...

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

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

  6. 「考试」noip模拟9,11,13

    9.1 辣鸡 可以把答案分成 每个矩形内部连线 和 矩形之间的连线 两部分 前半部分即为\(2(w-1)(h-1)\),后半部分可以模拟求(就是讨论四种相邻的情况) 如果\(n^2\)选择暴力模拟是有 ...

  7. 6.11考试总结(NOIP模拟7)

    背景 时间分配与得分成反比,T1 20min 73pts,T2 1h 30pts,T3 2h 15pts(没有更新tot值,本来应该是40pts的,算是本次考试中最遗憾的地方了吧),改起来就是T3比较 ...

  8. 6.10考试总结(NOIP模拟6)

    前言 就这题考的不咋样果然还挺难改的.. T1 辣鸡 前言 我做梦都没想到这题正解是模拟,打模拟赛的时候看错题面以为是\(n\times n\)的矩阵,喜提0pts. 解题思路 氢键的数量计算起来无非 ...

  9. 6.7考试总结(NOIP模拟5)

    前言 昨天说好不考试来着,昨晚就晚睡颓了一会,今天遭报应了,也没好好考,考得挺烂的就不多说了. T1 string 解题思路 比赛上第一想法就是打一发sort,直接暴力,然后完美TLE40pts,这一 ...

随机推荐

  1. flex布局的使用

    一.Flex布局是什么? Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为Flex布局. .box{ disp ...

  2. Windows反调试技术(下)

    OD的DBGHELP模块 检测DBGHELP模块,此模块是用来加载调试符号的,所以一般加载此模块的进程的进程就是调试器.绕过方法也很简单,将DBGHELP.DLL改名. #include <Wi ...

  3. 测试中常用的链接URL----方便自己查找

    1.TesterHome:https://testerhome.com/ 2.selenium的操作手册:https://selenium-python.readthedocs.io/ 3.

  4. 3. java基础语法

    3.1 注释(理解) 注释是对代码的解释和说明文字,可以提高程序的可读性,因此在程序中添加必要的注释文字十分重要.Java中的 注释分为三种: 单行注释.单行注释的格式是使用//,从//开始至本行结尾 ...

  5. [刷题] 46 Permutations

    要求 整型数组,每个元素不相同,返回元素所有排列的可能 示例 [1,2,3] [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ] 思路 树 ...

  6. centOS 7 安装 CUPS 打印服务器,安装映美 FP-730K打印机共享

    centOS 7 安装 CUPS 打印服务器,安装映美 FP-730K打印机共享 2017-09-13 16:27:02 mostone 阅读数 3698   版权声明:本文为博主原创文章,遵循CC ...

  7. Windows10查看电脑的USB接口是2.0还是3.0

    Windows10查看电脑的USB接口是2.0还是3.0原创小晓酱手记 最后发布于2019-08-22 16:09:48 阅读数 3662 收藏展开 同事要拷贝资料给我,问我电脑的USB接口是2.0还 ...

  8. Prometheus 通过 consul 实现自动服务发现

    1.Consul 介绍 Consul 是基于 GO 语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册.服务发现和配置管理的功能.Consul 提供服务注册/发现.健康检查.Key/Valu ...

  9. 11.8 iotop:动态显示磁盘I/O统计信息

    iotop命令是一款实时监控磁盘I/O的工具,但必须以root用户的身份运行.使用iotop命令可以很方便地查看每个进程使用磁盘I/O的情况. 最小化安装系统一般是没有这个命令的,需要使用yum命令额 ...

  10. git/repo常用命令

    Git作为广受欢迎的一款版本控制工具,它该如何通过命令行使用呢?本文为你揭晓浓缩精华精华版:git常用命令一览,含部分repo操作. 代码下载 repo init -- -->初始化需要下载的分 ...