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. L SERVER 数据库被标记为“可疑”的解决办法

    问题背景: 日常对Sql Server 2005关系数据库进行操作时,有时对数据库(如:Sharepoint网站配置数据库名Sharepoint_Config)进行些不正常操作如数据库在读写时而无故停 ...

  2. Python中的迭代器、生成器、装饰器

    1. 迭代器  1 """ 2 iterator 3 迭代器协议: 对象必须提供一个next()方法,执行该方法要么返回迭代中的下一项,要么引起一个StopIterati ...

  3. [刷题] 46 Permutations

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

  4. crontab简单使用手册

    Linux定时任务(1)- crontab 枫林风雨关注 0.1682018.12.14 12:29:47字数 946阅读 921 执行定时任务 crontab 执行循环任务 at 执行一次性任务 c ...

  5. 如何访问pod --- service(7)

    一.通过service访问pod 我们不应该期望 Kubernetes Pod 是健壮的,而是要假设 Pod 中的容器很可能因为各种原因发生故障而死掉.Deployment 等 controller ...

  6. Scala 关键字

    Java关键字 Java 一共有 50 个关键字(keywords),其中有 2 个是保留字,目前还不曾用到:goto 和 const.true.false 和 null 看起来很像关键字,但实际上只 ...

  7. Socket编程——(转载)

    我们深谙信息交流的价值,那网络中进程之间如何通信,如我们每天打开浏览器浏览网页时,浏览器的进程怎么与web服务器通信的?当你用QQ聊天时,QQ进程怎么与服务器或你好友所在的QQ进程通信?这些都得靠so ...

  8. Java中JDK,JRE和JVM之间的关系-(转载)

    初学JAVA很容易被其中的很多概念弄的傻傻分不清楚,首先从概念上理解一下吧,JDK(Java Development Kit)简单理解就是Java开发工具包,JRE(Java Runtime Envi ...

  9. 10.6 ip:网络配置工具

    ip命令是iproute软件包中的一个强大的网络配置工具,用于显示或管理Linux系统的路由.网络设备.策略路由和隧道.   ip [option] [object] [command] ip [选项 ...

  10. Centos6.5 修改主机名(hostname)

    centos6需要修改两处:一处是/etc/sysconfig/network,另一处是/etc/hosts,只修改任一处会导致系统启动异常.首先切换到root用户. /etc/sysconfig/n ...