【Codeforces】Codeforces Round #742 (Div. 2) C. Carrying Conundrum | 动态规划、思维

73 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

【Codeforces】Codeforces Round #742 (Div. 2) C. Carrying Conundrum | 动态规划、思维

题目链接

Problem - 1567C - Codeforces

题目

image.png

题目大意

对于给定的 nn 输出满足 a+b=na+b=n 的不同有序正整数对 (a,b)(a,b) 的数量,在本题中 + 的进位规则从“满 10 向高一位进 1”变为“满 10 向高二位进 1”。如 5+5=1005+5=100

动态规划

思路

一开始读懂题没敢下手做,不理解数据范围为啥只给到 n109n\le 10^9,感觉 lg(n)105lg(n)\le 10^5 比较合适 QAQ

容易发现虽然这个题里的进位规则有所改变,但依然是要么进 1 要么不进位。所以我们可以考虑 DP。将 nn 由低位向高位写成 a1,a2,...,atota_1,a_2,...,a_{tot}。令 dp[i][0]dp[i][0] 表示前 ii 个元素乱选且满足要求的方案其中第 ii 位不进位,dp[i][1]dp[i][1] 表示前 ii 个元素乱选且满足要求的方案其中第 ii 位进位。怎么转移呢?

首先手玩出两个一位数相加和为 xx 的方案放在数组 qwq[x]qwq[x] 里,然后我们从低到高遍历输入的 nn 的每一位 ii,显然有(即从 i2i-2 进不进位分别转移):

  • dp[i][0]=qwq[a[i]]×dp[i2][0]+qwq[a[i]1]×dp[i2][1]dp[i][0]=qwq[a[i]]\times dp[i-2][0]+qwq[a[i]-1]\times dp[i-2][1]
  • dp[i][1]=qwq[a[i]+10]×dp[i2][0]+qwq[a[i]+9]×dp[i2][1]dp[i][1]=qwq[a[i]+10]\times dp[i-2][0]+qwq[a[i]+9]\times dp[i-2][1]

容易发现奇偶位置方案相互独立,由乘法原理最终的方案为 dp[tot][0]×dp[tot1][0]dp[tot][0]\times dp[tot-1][0]

注意:

  • 转移和输出答案过程中可能出现越界问题,需要进行特判。
  • 模数1e9+91e9+9……
  • 由于要求 aabb 均为正整数,答案需要减去带有 0 的情况,所以应该输出 dp[tot][0]×dp[tot1][0]2dp[tot][0]\times dp[tot-1][0]-2

代码

#include <iostream>
#include <algorithm>
#include <math.h>
#include <stdio.h>
#include <map>
#include <vector>
#include <queue>
using namespace std;
using LL=long long;
const int N=11;
int n,tot,a[N];
LL dp[N][2];
LL qwq[21]={1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1,0};
LL solve()
{
	scanf("%d",&n);
	for (tot=0;n;n/=10) a[++tot]=n%10;
	dp[1][0]=qwq[a[1]];
	dp[1][1]=qwq[a[1]+10];
	if (tot==1) return printf("%d\n",dp[1][0]-2),0;
	dp[2][0]=qwq[a[2]];
	dp[2][1]=qwq[a[2]+10];
	for (int i=3;i<=tot;++i)
	{
		dp[i][0]=qwq[a[i]]*dp[i-2][0];
		if (a[i]) dp[i][0]+=qwq[a[i]-1]*dp[i-2][1];
		dp[i][1]=qwq[a[i]+10]*dp[i-2][0]+qwq[a[i]+9]*dp[i-2][1];
	}
	printf("%lld\n",dp[tot][0]*dp[tot-1][0]-2);
        return 0;
}
int main()
{
	int T=1;
	scanf("%d",&T);
	while (T--) solve();
	return 0;
}

推式子直接输出

思路

看了题解大惊失色(

我们刚才指出了

容易发现奇偶位置方案相互独立

那么实际上将 nn 的每个数位直接按照奇偶分开,顺序连成两个数字 n1n_1n2n_2,原先的进两位就变成的普通的进位……如 1234512345 可以划分成 1351352424。那么一个数字 xx 划分成两个数之和的方案数显然就是 x+1x+1,所以直接输出 (n1+1)×(n2+1)2(n_1+1)\times(n_2+1)-2 即可。