首页 > 其他分享 >ABC322G题解

ABC322G题解

时间:2023-10-01 16:44:52浏览次数:44  
标签:10 return int 题解 ll mid 300 ABC322G

这场的G怎么这么毒瘤啊/kk
听说正解是DP?我爆搜头一个表示不服!

statement

找出三元组 \((S, a, b)\) 的数量,使得 \(S\) 在 \(a\) 进制下和在 \(b\) 进制下的差为 \(X\) ,其中 \(0 \leq S_i <(min(a, b, 10))\) 。

首先因为 \(X > 0\) 显然 \(S\) 不可能为 \(1\) 位数。
如果 \(S\) 为两位数,那么可以枚举 \(S\) 的十位 \(n\) ,显然满足 \(n(a - b) = X\) ,这种情况对答案的贡献是 \(min(10, b)\) 。可以把 \(b < 10\) 和 \(b \geq 10\) 分开计算。
如果 \(S\) 为三位数,可以验证 \(a,b \leq 1e5\) 。那么枚举十位 \(n\) ,百位 \(m\) 和 \(a\) ,这个时候如果存在 \(b\) 那么 \(b\) 唯一,可以通过二分求出。这种情况还是贡献 \(min(10, b)\) 。
如果 \(S\) 的位数 \(>3\) ,感性理解一下就能知道合法的三元组非常少。事实上,通过在计算器上二分可以得知,在 \(\mid S \mid = 4\) 的时候 \(a, b \leq 300\) ,在 \(\mid S \mid = 5\) 的时候 \(a, b \leq 40\) 。这个范围不禁想让我们枚举 \(S, a, b\) 。
但是经过计算, \(S\) 的位数最高可以达到 \(12\) ,在最高位填 \(1\) , \(a,b\) 分别取 \(3, 2\) 时取得。
你肯定发现了,如果位数很高,其实没有必要每一位填 \((0, 9)\) 中的每一个数。那么在已经填好的数 \(\geq\) 当前可能的最大进制的时候可以剪枝。
那么现在就可以在 略长于时限的时间内 跑完了。接下来我们还是老办法,不枚举第一位,改为在最后加上 \(min(10, b)\) 就可以 通过 这道题了。

注意实现时的一车细节。复杂度 \(\Theta(勉强能跑)\)

赠送一张表,是我估算的每一个位数下可能存在的最高进制。

位数 4 5 6 7 8 9 10 11 12
最高进制 300 40 16 8 6 4 3 3 3

后话:我在场上的初步想出并实现了这个做法,这道题和题解是第二天写完的。
如果思考能够更缜密,
实现能够更迅速,,
细节能够更准确,,,
或许结局就会不一样吧?

\(\textcolor{green}{CSP2023rp++}\)

code:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int P = 998244353;
const int N = 2e5+5;
template<typename T>inline void read(T &a)
{
	a = 0;
	int f = 1;
	char c = getchar();
	while(!isdigit(c))
	{
		if(c == '-')	f = -1;
		c = getchar();
	}
	while(isdigit(c))
		a = a * 10 + c - 48,c = getchar();
	a *= f;
}

template<typename T,typename ...L> inline void read(T &a,L &...l)
{
	read(a),read(l...);
}

inline int Mul(int a, int b) {
	return (long long)a * b % P; 
}

inline int Add(int a, int b) {
	return a + b >= P ? a + b - P : a + b;
}

inline void Inc(int &a, int b) {
	a = Add(a, b);
}

const int dx[] = {300, 300, 300, 300, 40, 16, 8, 6, 4, 3, 3, 3};

int n, X, ans;
int qp[13][505];

ll f(ll i, ll j, int x) {
	return i * x * x + j * x;
}

ll f2(vector <int> &a, int b) {
	ll ans = 0;
	for(int i = 0; i < int(a.size()); i++) {
		ans += qp[i][b] * a[i];
	} 
	return ans;
}

void DFS(vector<int> a, int pos) {
	if(pos == 12) {
		return;
	}
	if(*max_element(a.begin(), a.end()) >= dx[pos]) return;
	//cerr<<a.size()<<' '<<pos<<endl;
	for(int i = 0; i < min(min(10, dx[pos]), n); i++) {
		a.emplace_back(i);
		if(pos >= 3 && a[pos]) {
			for(int l = *max_element(a.begin(), a.end()) + 1; l <= min(dx[pos], n); l++) {//下界 
				for(int j = i + 1; j <= min(dx[pos], n); j++) {
					if(f2(a, j) - f2(a, l) == X) {
						Inc(ans, min(l, 10));
					} 
				}
			} 
		}
		DFS(a, pos + 1); 
		a.pop_back(); 
	}
}

int main() {
	read(n, X);
	for(int i = 0; i <= 11; i++) {
		for(int j = 1; j <= dx[i]; j++) {
			int k = 1, res = i;
			while(res--) {
				k *= j;
			} 
			qp[i][j] = k;
		}
	}
	vector<int> tmp;
	tmp.emplace_back(0); 
	DFS(tmp, 1);//不填第0位 
	for(int i = 1; i <= 9; i++) {
		for(int j = 0; j <= 9; j++) {
				//三位整数
			for(int x = max(i, j) + 2; x <= min(100005, n); x++) {
				int l = max(max(i, j) + 1, 2), r = x - 1, mid;
				while(l < r) {
					int mid = (l + r + 1) >> 1;
					if(f(i, j, x) - f(i, j, mid) < X) {
						r = mid - 1;
					}
					else {
						l = mid;
					}
				}
				if(f(i, j, x) - f(i, j, l) == X) {
					Inc(ans, min(10, l));
				}
			}
		}
	}
	for(int i = 1; i <= 9; i++) {
		for(int k = i + 1; k < min(10, n + 1); k++) {
			if(X % i == 0 && k + (X / i) <= n) {
				Inc(ans, k);
			}
		} 
		if(X % i == 0) {
			Inc(ans, Mul(10, max(0, n - (X / i) - 10 + 1)));
		} 
	}
	cout<<ans<<endl;
} 

/*
	start coding at:
	finish debugging at:2023/10/1 16:00 
	stubid mistakes:DFS里push_back没有回溯 ,二分里面调用了mid(90%的程序员写不对二分。。。) ,循环变量重名,贡献没有和10取min 
*/

/*
  吾日三省吾身:
  你排序了吗?
  你取模了吗?
  你用%lld输出long long 了吗?
  1LL<<x写对了吗?
  判断=0用了abs()吗?
  算组合数判了a<b吗?
  线段树build()了吗?
  .size()加了(signed)吗?
  树链剖分的DFS序是在第二次更新的吗?
  修改在询问前面吗?
  线段树合并到叶子结点return了吗?
  __builtin_ctz后面需要加ll吗?
*/


标签:10,return,int,题解,ll,mid,300,ABC322G
From: https://www.cnblogs.com/miloHogwarts4ever/p/ABC322G.html

相关文章

  • 「题解」Codeforces Round 895 (Div. 3)
    A.TwoVesselsProblem题目Sol&Code签到题#include<bits/stdc++.h>typedeflonglongll;intmin(inta,intb){returna<b?a:b;}intmax(inta,intb){returna>b?a:b;}intT,a,b,c;intmain(){scanf("%d"......
  • AT_abc254_h [ABC254Ex] Multiply or Divide by 2 题解
    打篇题解巩固一下。题意给你两个集合\(A\)和\(B\),对于任意\(A\)集合中的元素,我们可以进行\(2\)种操作:\(a_i\gets\left\lfloor\frac{a_i}{2}\right\rfloor\)或\(a_i\gets2\timesa_i\)。问最少要多少次才能使\(A\)和\(B\)中的元素相等。分析首先我们可以令\(a......
  • UVA12655 Trucks 题解
    题目传送门前言中文题目可以看link。前置知识Kruskal重构树|最近公共祖先简化题意给定一个\(N\)个点\(M\)条边的有向图,共有\(S\)次询问,每次询问从\(L\)到\(H\)所有的路径中最小的权值的最大值(多组数据)。本题即最大瓶颈路问题。解法使最小的权值最大,不难......
  • 【洛谷 P1305】新二叉树 题解(结构体数组+先序遍历+二叉树)
    新二叉树题目描述输入一串二叉树,输出其前序遍历。输入格式第一行为二叉树的节点数。()后面行,每一个字母为节点,后两个字母分别为其左右儿子。特别地,数据保证第一行读入的节点必为根节点。空节点用*表示输出格式二叉树的前序遍历。样例#1样例输入#16abcbdicj*d**i**j**......
  • SP16113 SUBTLEBA - Trucks Transportation 题解
    题目传送门前言本题样例有问题,如果想要样例可以去vjudge上。本题提交后可能会出现UKE,建议前往link提交,而且本篇题解中所提供的代码也为link代码。前置知识Kruskal重构树|最近公共祖先简化题意给定一个\(N\)个点\(M\)条边的有向图,共有\(S\)次询问,每次询问......
  • 题解 CF1875D【Jellyfish and Mex】
    显然,除非\(\operatorname{mex}a=0\),否则不会删除\(>\operatorname{mex}a\)的数。而\(\operatorname{mex}a=0\)时不对答案产生贡献,因此任意时刻我们都可以忽略\(a\)中\(>\operatorname{mex}a\)的数。又显然,一旦我们开始删一个数,就会先把所有与之相等的数删光。否则,设最先......
  • counting题解
    \(N,M\le1e7\)接着反射容斥,考虑这道题怎么做如果去枚举不动步数,加上反射容斥,直接T飞了把-1/0/1操作转换一下,就成了0/1/2如果没有限制(不能<0或>m),n步方案就是\((1+x+x^2)^n\)设\(H=1+x+x^2\quadF=H^n\)那么对两边求导:\[nH^{n-1}H'=F'\]\[F'H=nFH'\]我们知道\[H=1+x+x^2......
  • 第四周题解
    第四周题解7-1根据后续和中序遍历输出先序遍历利用数组保存树的后序遍历和中序遍历,根据后续遍历和中序遍历的特点还原树,并根据先序遍历的顺序,即根左右,利用函数递归输出打印,注意输出格式的正确性。#include<bits/stdc++.h>usingnamespacestd;constintN=40;typedeflon......
  • vs code调试rust乱码问题解决方案
    在terminal中用chcp65001修改一下字符集,就行了。有的博主推荐修改区域中的设置,这会引来很大的问题。千万不要修改如下设置:......
  • P7167 [eJOI2020 Day1] Fountain 题解
    Description给定\(n\)个从上往下圆心重叠的圆盘,给定每个圆盘的直径\(d_i\)和容量\(c_i\),所有圆盘底下有一个容量为\(\infty\)的水池,编号为\(0\)。\(q\)次询问,每次给定\(r\)和\(v\)表示往第\(r\)个圆盘里倒\(v\)的水,输出水最后流到哪个圆盘会停止。Solution倍......