Atcoder agc035E

好题。
先考虑给定一个删除的元素集合,怎么判断是否能构造出来。对于一个给定的能构造出某个集合的最短操作序列,我们发现每个元素被删除后就不会再加入了,否则可以得到更短的操作序列。那么对删除的元素集合中,若存在两个数 u u u v v v,且 v = u + 2 v=u+2 v=u+2 v = u − K v=u-K v=uK,我们就从 u u u v v v连一条边,可以构造出来当且仅当这样得到的图是DAG。
K K K为偶数,显然可以分开奇偶考虑,这样合法的条件就是选择的集合中不能有连续的 K 2 \frac{K}{2} 2K个奇数或偶数存在,随便DP一下就好了。
K K K为奇数,我们将奇数和偶数分别排开,得到了两条链,那么一个不合法的环显然同时存在奇数和偶数。我们容易证明如果存在环,那么一定存在只会切换两次的环(也即 u − ( u + 2 ) − ( u + 4 ) − . . . − ( u + 2 t ) − ( u + 2 t − K ) − ( u + 2 t − K + 2 ) − . . . ( u + K ) − u u-(u+2)-(u+4)-...-(u+2t)-(u+2t-K)-(u+2t-K+2)-...(u+K)-u u(u+2)(u+4)...(u+2t)(u+2tK)(u+2tK+2)...(u+K)u)。这样就容易DP了,我们设 F [ i ] [ j ] [ k ] F[i][j][k] F[i][j][k]表示考虑了第一条链的前 i i i个数和第二条链的前 i + ⌊ K 2 ⌋ i+\lfloor \frac{K}{2}\rfloor i+2K个数,第一条链从 i i i连续向后取了 j j j个数,第二条链从 i + ⌊ K 2 ⌋ i+\lfloor \frac{K}{2}\rfloor i+2K连续向前取了k个数,转移讨论一下两条链分别下一个取不取即可(只考虑环中有一条经过这两个数的情况)。
时间复杂度 O ( n 3 ) \mathcal O(n^3) O(n3)

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int MOD;

inline void add(int &x,int y) {
  ((x+=y)>=MOD)?x-=MOD:0;
}

int f[2][155][155],g[155][155];

int dp1(int n,int m) {
  if (m>n-2) {
  	int s=1;
  	for(int i=1;i<=n;i++) s=s*2LL%MOD;
  	return s;
  }
  m>>=1;
  int u=((n+1)>>1),v=n-u,cur=0;
  for(int i=0;i<=u;i++) f[0][i][0]=1;
  for(int i=1;i<=m;i++) {
  	cur^=1;
  	memset(f[cur],0,sizeof(f[cur]));
  	for(int j=0;j<=u;j++)
  	for(int k=0;k<i;k++)
  	  if (f[cur^1][j][k]) {
  	  	  add(f[cur][j][0],f[cur^1][j][k]);
  	  	  add(f[cur][j][k+1],f[cur^1][j][k]);
		}
  }
  for(int i=m+1;i<=v;i++) {
  	cur^=1;
  	memset(f[cur],0,sizeof(f[cur]));
  	int r=u-i+m+1;
  	for(int j=1;j<=r;j++)
  	for(int k=0;k<i;k++)
  	  if (f[cur^1][j][k]) {
  	  	  add(f[cur][j-1][0],f[cur^1][j][k]);
  	  	  if (2*m-k+2>j) add(f[cur][j-1][k+1],f[cur^1][j][k]);
		}
	for(int j=0;j<r;j++)
	for(int k=0;k<i;k++)
	  if (f[cur^1][0][k]) {
	  	  add(f[cur][j][0],f[cur^1][0][k]);
	  	  add(f[cur][j][k+1],f[cur^1][0][k]);
	  }
  }
  for(int i=v-m+1;i<=u;i++) {
  	cur^=1;
  	memset(f[cur],0,sizeof(f[cur]));
  	int r=u-i+1;
  	for(int j=1;j<=r;j++)
  	for(int k=0;k<=v;k++)
  	  if (f[cur^1][j][k]) add(f[cur][j-1][k],f[cur^1][j][k]);
  	for(int j=0;j<r;j++)
  	for(int k=0;k<=v;k++)
  	  if (f[cur^1][0][k]) add(f[cur][j][k],f[cur^1][0][k]);
  }
  int ans=0;
  for(int i=0;i<=v;i++) add(ans,f[cur][0][i]);
  return ans;
}

int dp2(int n,int m) {
  memset(g,0,sizeof(g));
  g[0][0]=1;
  for(int i=0;i<n;i++)
    for(int j=0;j<=i;j++)
      if (g[i][j]) {
      	add(g[i+1][0],g[i][j]);
      	if (j<m) add(g[i+1][j+1],g[i][j]);
	  }
  int ans=0;
  for(int i=0;i<=n;i++) add(ans,g[n][i]);
  return ans;
}

int main() {
  int n,m;
  scanf("%d%d%d",&n,&m,&MOD);
  if (m&1) printf("%d\n",dp1(n,m));
  else printf("%lld\n",(ll)dp2((n+1)>>1,m>>1)*dp2(n>>1,m>>1)%MOD);
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Matlab中,AGC(Automatic Gain Control)是一种用于自动调节信号增益的技术AGC系统的作用是保持信号在一个适当的功率范围内,以便有效地处理和分析信号。使用Matlab可以实现数字AGC系统的建模与仿真。 在Matlab中使用Simulink环境进行数字AGC的建模与仿真可以通过以下步骤实现: 1. 使用Simulink库中的信号源模块生成输入信号。可以使用随机信号或特定模式的信号作为输入。 2. 将信号传递到AGC模块,该模块可以从Simulink库中选择或自定义。 3. 配置AGC模块的参数,例如增益平均系数、增加步进、减小步进、参考级别、上限和下限等。 4. 将AGC模块的输出与其他模块连接,例如显示模块或数据处理模块。 5. 运行模型并观察AGC系统的输出结果。 通过以上步骤,您可以使用Matlab中的Simulink环境建立数字AGC模型,并使用Matlab实现数字AGC系统。需要注意的是,在实际应用中,数字AGC系统的复杂程度可能会更高,需要根据具体情况进行调整和优化。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [基于Simulink的数字AGC建模与仿真](https://blog.csdn.net/CodeWG/article/details/130591628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值