首页 > 其他分享 >ABC317F题解

ABC317F题解

时间:2023-08-27 22:23:21浏览次数:40  
标签:int 题解 ABC317F deep lim2 m1 m3 m2

让人头大的数位DP。建议评蓝。个人认为不适合放ABC的F。

将三个数二进制拆分,使三个数异或为0相当于每个二进制位三个数中有0或2个是1。

所以考虑数位DP,设 \(dp[i][m1][m2][m3][lim1][lim2][lim3]\) 为第 \(i\) 位,三个数模 \(a\) , \(b\) , \(c\) 分别是 \(m1\) , \(m2\) , \(m3\) ,以及三个数有没有最高位限制。

这道题比较特殊。仔细想想可以发现这道题最高位限制必须放状态里。

下文设 \(A[i]\) 为 \(n\) 的第 \(i\) 位。

马上烧脑起来了。

一个状态 \(dp[i][m1][m2][m3][lim1][lim2][lim3]\) 可以如此转移过来:

若 \(A[i]=1\) :

首先,\(dp[i-1][m1][m2][m3][0][0][0]\) 可以对状态产生贡献,对应三个数的第 \(i\) 位全部为 \(0\) 的情况。

然后继续分类讨论三种情况,这里举例一种。

若 \(lim1=0\) 且 \(lim2=0\) :

则 \(dp[i-1][(m1+(1<<i))\mod a][(m2+(1<<i))\mod b][m3][lim1\ \And\ !A[i]][lim2][lim3]\) 可以贡献。对应 \(x1\) , \(x2\) 的第 \(i\) 位为1,\(x3\) 的第 \(i\) 位为0的情况。

另外两个情况,同理。

若 \(A[i]=0\) :

那么就只有 \(dp[i-1][m1][m2][m3][lim1][lim2][lim3]\) 可以对状态产生贡献,还是对应三个数的第 \(i\) 位全部为 \(0\) 的情况,只是三个高位限制不一样了。

最核心的DP转移到这里就完了。还没完,我们又发现我们还要减去三个数中有数为0的情况。

为此还要再跑一次数位DP专门处理。枚举 \(x1\) , \(x2\) , \(x3\) 为0的情况。

举个例子,现在考虑的是 \(x3\) 为0,那么就设 \(dp2[i][m1][m2]\) 为第 \(i\) 位, \(x1\) , \(x2\) 模 \(a\) , \(b\) 为 \(m1\) , \(m2\) 的情况。

这个DP很简单,并没有分类讨论。

\(dp2[i][m1][m2]=dp2[i-1][(m1+(1<<i))\mod a][(m2+(1<<i))\mod b]\)

\(x1\) , \(x2\) 为0还是同理。

像这样跑三次就可以求出三个数中有数为0的不合法贡献。

最后还有一个细节就是这样会把三个数全0的情况算三次,加回去2即可。

code

丑。

//writer:Oier_szc

#include <bits/stdc++.h>
#define TS puts("I AK IOI");
#define int long long
using namespace std;
const int N=2005,mod=998244353;
int n,a,b,c,ans=0;
int dp[70][15][15][15][2][2][2];
int A[70],yes[70],len=-1;
int dfs(int deep,int m1,int m2,int m3,bool lim1,bool lim2,bool lim3)
{
	if(deep==-1) return m1==0&&m2==0&&m3==0;
	if(dp[deep][m1][m2][m3][lim1][lim2][lim3]!=-1) return dp[deep][m1][m2][m3][lim1][lim2][lim3];
	int res=0;
	if(A[deep]) res=(res+dfs(deep-1,m1,m2,m3,0,0,0))%mod;
	else res=(res+dfs(deep-1,m1,m2,m3,lim1,lim2,lim3))%mod;
	if(A[deep]||(!lim2&&!lim3)) res=(res+dfs(deep-1,m1,(m2+(1ll<<deep))%b,(m3+(1ll<<deep))%c,lim1&&!A[deep],lim2,lim3))%mod;
	if(A[deep]||(!lim1&&!lim3)) res=(res+dfs(deep-1,(m1+(1ll<<deep))%a,m2,(m3+(1ll<<deep))%c,lim1,lim2&&!A[deep],lim3))%mod;
	if(A[deep]||(!lim1&&!lim2)) res=(res+dfs(deep-1,(m1+(1ll<<deep))%a,(m2+(1ll<<deep))%b,m3,lim1,lim2,lim3&&!A[deep]))%mod;
	dp[deep][m1][m2][m3][lim1][lim2][lim3]=res;
	return res;
}
int dp2[70][15][15],M1,M2;
int dfs2(int deep,int m1,int m2,int lim)
{
	if(deep==-1) return m1==0&&m2==0;
	if(dp2[deep][m1][m2]!=-1&&!lim) return dp2[deep][m1][m2];
	int up=lim?A[deep]:1ll,res=0;
	for(int i=0;i<=up;++i)
	{
		res+=dfs2(deep-1,(m1+(i<<deep))%M1,(m2+(i<<deep))%M2,lim&&i==up);
	}
	if(!lim) dp2[deep][m1][m2]=res;
	return res;
}
signed main()
{
	scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
	while(n)
	{
		A[++len]=n%2;
		n/=2;
	}
	int cnt_0=-2;
	M1=a,M2=b;
	memset(dp2,-1,sizeof(dp2));
	cnt_0=(cnt_0+dfs2(len,0,0,1))%mod;
	M1=a,M2=c;
	memset(dp2,-1,sizeof(dp2));
	cnt_0=(cnt_0+dfs2(len,0,0,1))%mod;
	M1=b,M2=c;
	memset(dp2,-1,sizeof(dp2));
	cnt_0=(cnt_0+dfs2(len,0,0,1))%mod;
	memset(dp,-1,sizeof(dp));
	printf("%lld\n",(dfs(len,0,0,0,1,1,1)-cnt_0+mod)%mod);
	return 0;
}

标签:int,题解,ABC317F,deep,lim2,m1,m3,m2
From: https://www.cnblogs.com/StevenZC/p/17660998.html

相关文章

  • NOIP2013提高组初赛易错题解析
    7. 正解:可以画出递归树,画出后应该是这样子的 画出递归树,就可以得出答案时间复杂度为O(Fn) 15. 正解:2T(n/2)=O(logn)T(n)=2*T(n/2)+2*n=O(nlogn)三.2. 错误原因:蒙的正解:通过观察,可以找到递推关系式,f[n]=1/n*(n+f[1]+f[2]+...+f[n]),f[1]=0,f[2]=2,经过计算......
  • NOIP2017提高组初赛易错题解析
     8.由四个不同的点构成的简单无向连通图的个数是()A.32 B.35 C.38 D.41错误原因:数重了正解:分情况计算,6条边的有1种,5条边的有C(6,1)=6种,4条边的有C(6,4)=15种,3条边,要分度数,2+2+1+1的有12种,3+1+1+1的有4种,共38种 10.若 f0​=0,f1​=1,fn+1​=(fn​+fn−1)/2​​,则随着......
  • NOIP2016提高组初赛易错题解析
    9. 正解:每一个bit,都有两种可能,0和1,所以最多可以使用232=4GB的内存 14. 正解:使用代入法,T(n)=2T(n/4)+sqrt(n),T(n/16)=2T(n/4/4/4)+1/4*sqrt(n),T(n)=2k+k*sqrt(n)=sqrt(n)+k*sqrt(n),则时间复杂度为O(sqrt(n)logn) 二.1. 正解:前三个都是无线通信技术,以太网是有......
  • NOIP2018提高组初赛易错题解析
    2.下列属于解释执行的程序设计语言是()A.C B.C++ C.Pascal D.Python错误原因:忘记了正解:C、C++和Pascal都是编译性语言,而Python是解释性语言 5.设某算法的时间复杂度函数的递推方程是 T(n)=T(n-1)+n(n 为正整数)及 T(0)=1,则该算法的时间复杂度为()A.O(logn) ......
  • P7414 [USACO21FEB] Modern Art 3 G 题解
    思路考虑区间DP。设\(f_{i,j}\)表示要刷到\([i,j]\)这一段的目标需要的最小次数。对于\(f_{i,j}\),如果\(color_i\)与\(color_j\)相等,那么再子区间合并的时候就可以少刷一次,即\(f_{i,j}=\min\limits_{k=i}^{j-1}f_{i,k}+f_{k+1,j}-1\)。否则\(f......
  • CSP-J2022初赛易错题解析
    7.假设字母表{a,b,c,d,e}在字符串出现的频率分别为10%,15%,30%,16%,29%。若使用哈夫曼编码方式对字母进行不定长的二进制编码,字母d的编码长度()位。A.1  B.2 C.2或3  D.3正解:画出哈夫曼树即可9.考虑由N个顶点构成的有向连通图,采用邻接矩阵的数据结构表示时,该矩阵中至......
  • CSP-J2020初赛易错题解析
    一.5. 正解:冒泡排序最少比较n-1次,即单调上升序列 10.5 个小朋友并排站成一列,其中有两个小朋友是双胞胎,如果要求这两个双胞胎必须相邻,则有()种不同排列方法?A.24 B.36 C.72 D.48错误原因:忘记乘上A(2,2)了正解:捆绑法,A(4,4)*A(2,2)=48 15.有五副不同颜色的手套(......
  • CSP-J2021初赛易错题解析
    12.由 1,1,2,2,3 这五个数字组成不同的三位数有()种。A.18 B.15 C.12 D.24正解:枚举法,枚举即可,共18种 15.有四个人要从A点坐一条船过河到B点,船一开始在A点。该船一次最多可坐两个人。已知这四个人中每个人独自坐船的过河时间分别为 1,2,4,8,且两个人坐船的......
  • 【题解】 P7077 [CSP-S2020] 函数调用(拓扑排序)
    题意题目给定了一个长度为\(n\)序列\(a\)与\(m\)个操作,操作一共有3种:1.给定\(x,y\),使\(a_x\)增加\(y\)。2.给定\(x\),使\(a\)中所有数全部乘上\(x\)。3.给出k个数\(c_1,c_2,...,c_k\),表示这个操作的任务是按照先后顺序执行编号为\(c_1,c_2,...,c_k\)的\(k\)的操作。最后,题目相......
  • P2049 魔术棋子题解
    思路设\(f_{i,j,k}\)表示从原点走到\((i,j)\)模\(m\)后的乘积为\(k\)的方案数。状态转移:\(f_{i,j,ka_{i,j}\bmodm}=f_{i-1,j,k}+f_{i,j-1,k}\)统计答案:\(f_{n,n,k}\)。代码#include<bits/stdc++.h>usingnamespacestd;constintN=110......