[HNOI2002]奶牛的运算

题目链接

1|0Solution

陈年老题了,但真是一道组合数好题。

根据数学知识,加括号就相当于改变里面的符号,所以我们可以将其看为对符号的修改,问题就变为:一个长度为 n1 的符号序列,每次可以选一个区间将其符号反转,问 k 次操作后,能得到多少不同的序列。

要注意第一个符号没有办法改变,这在最后会提到。

1|1引理

k 次对任意区间的操作可以看作不超过 k 次对互不相交且不相邻的区间的操作。

只考虑 2 个区间的情况即可推广,分情况讨论:

  1. 当区间不交时且不相邻时,可以通过相同的操作次数来实现相同的效果。
  2. 当区间有相交部分,例如 [1,5][3,7],容易发现对于相交的区间 [3,5] 被改了 2 次又被改回来了,就相当于只改变了 [1,2][6,7]。可以通过相同的操作次数来实现相同的效果,注意这里包含了一个区间是另一个区间子集的情况。
  3. 当区间相邻,如 [1,3][4,5],我们可以通过一次操作 [1,5] 即可实现相同效果。

1|2答案

这样就很清楚了,答案就是选择至多 k 个不交也不相邻区间的方案数,插板法即可。

注意第一个符号是不能改的,于是头不能插板,而尾插板有意义,所以有 n1 个位置,插至多 2×k 个偶数板,组合数即可,答案为:

i=02k(n1i)

注意增量 Δ=2

2|0Code

答案会很大,用高精,这里为了不占版面就不加了。

#include<bits/stdc++.h> using namespace std; void read(int &x) { char ch=getchar(); int r=0,w=1; while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar(); while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar(); x=r*w; } int C(int n,int m) { if(m==0)return 1; if(n<m)return 0; int ans=1; for(int i=1;i<=m;i++) ans*=(n-i+1),ans/=i; return ans; } int main() { int n,k; read(n);read(k); int ans=0; for(int i=0;i<=2*k;i+=2) ans+=C(n-1,i); cout<<ans; return 0; }

__EOF__

本文作者JMartin
本文链接https://www.cnblogs.com/LAK666/p/16613099.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Epoch_L  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示