ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Atcoder Beginner Contest 258 EX 题解

2022-07-13 21:07:31  阅读:140  来源: 互联网

标签:node Atcoder le 数列 Beginner 题解 奇偶性 dp 前缀


前言

这题有很高级的基于 \(Fibonacci\) 数列递推的做法,我提供一个简单做法。

那个高级做法的题解我附图在博客里面,不过禁止外传。

这个题矩阵加速的系数涉及到能不能选,按照不能选的数分段矩阵求幂是一个不错的方法

难度

差不多 \(2400\) 。

题意

给定 \(n,S\) 和一个数列 \(A\) ,已知数列 \(X\) 中每个数都是正奇数,所有数的和是 \(S\) ,任意一个前缀和不在数列 \(A\) 中,求这样的数列的个数。

$1\le n\le 1e5 $ \(1 \le S \le 1e18\) 。

题解

首先注意到一个比较 \(sb\) 的 \(DP\) ,设 \(f[i][j]\) 表示填了前 \(i\) 个数,和是 \(j\) 的方案数,复杂度很高,肯定不过。

考虑转化题意,题目限制了前缀和不能是 \(A\) 中的数,那我们考虑选前缀和来构成数列,那么限制就变成了不能选 \(A\) 中的数,然后就是,没有数的情况下和是 \(0\) ,整个数列选完了的情况下和是 \(S\) ,所以 \(0,S\) 必选。

因为所有数都是正奇数,那么前缀和肯定是奇数偶数交替出现的,所以相邻两个数必须奇偶性不同才是合法方案。

至此,我们巧妙地转化了题意与限制。

然后我们用一个 \(DP\) 来计数,设 \(dp[i][1/0]\) 表示已经填好了数列 \(X\) 中的某些数,最后填上的这个数和数字 \(i\) 的奇偶性是否相同。

转移方程:

\(dp[i][1]=dp[i-1][0]\) 。

\(dp[i][0]=dp[i-1][1]+dp[i-1][0]\) \(\times\) \([i不属于A]\) 。

大概解释一下,状态 \((i,1)\) 表示最后一个数和 \(i\) 奇偶性相同,那必然和 \(i-1\) 奇偶性不同,这个状态一定不会选进 \(i\) ,所以不担心 \(i\) 是否属于 \(A\) 。

状态 \((i,0)\) 就略显复杂,包含了部分不选 \(i\) 的情况,也即此处 \(dp[i-1][1]\) ,而选 \(i\) 则需要和上一个数奇偶性不同,也就是和 \(i-1\) 奇偶性相同,再注意一下 \(i\) 是不是在 \(A\) 中即可。

这个转移式,我觉得和 \(Fibonacci\) 数列有相似性,所以这个也是可以用矩阵加速的,每次求幂是 \(A_{i+1}-A_i-1\) 次,矩阵加速具体看我代码。

#include<bits/stdc++.h>
#define N 100005
#define p 998244353
#define ll long long
using namespace std;
ll n,a[N],s;
struct node
{
	ll m[2][2];
}A,B,C;
node mul(node a,node b)
{
	node c;
	memset(c.m,0,sizeof(c.m));
	for(int i=0;i<=1;i++)
	{
		for(int j=0;j<=1;j++)
		{
			for(int k=0;k<=1;k++) c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j]%p)%p;
		}
	}
	return c;
}
node ksm(node a,ll b)
{
	node c;
	memset(c.m,0,sizeof(c.m));
	for(int i=0;i<=1;i++) c.m[i][i]=1;
	while(b)
	{
		if(b&1) c=mul(c,a);
		a=mul(a,a);
		b=(b>>1);
	}
	return c;
}

int main()
{
	scanf("%lld%lld",&n,&s);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    A.m[0][0]=1;A.m[0][1]=1;A.m[1][0]=1;
    B.m[0][1]=1;B.m[1][0]=1;
    C.m[0][0]=1;
    for(int i=0;i<=n-1;i++)
    {
        C=mul(C,ksm(A,a[i+1]-a[i]-1));
        C=mul(C,B);
    }
    C=mul(C,ksm(A,s-a[n]));
	printf("%lld",C.m[0][1]);
    return 0;
}  

标签:node,Atcoder,le,数列,Beginner,题解,奇偶性,dp,前缀
来源: https://www.cnblogs.com/zhengenxi/p/16475544.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有