Hdu 1573 X问题

大意不再赘述。

思路:扩展欧几里得算法。

注意,题目要求的是正整数的个数,不包括0。

注意两种情况无解(解为0),一是c % d != 0,二是a > n。

令R数组中所有数的最小公倍数是lcm,方程在lcm范围内的+非负整数解是a,则有a + lcm*x <= n,若a != 0,则解得结果是x,否则为x-1(0不是正整数)

其中两个方程合并的结果为:C' ≡ C(mod B),B = lcm(R1,R2,R3,R4...,Rn);

所以C' = B*x + C,若lcm内的最小整数解为a,则所有的整数解为a + k*B (k = 0,1,2,3...)

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
using namespace std;

typedef __int64 LL;

const int MAXN = 110;

LL n;

int m;

LL lcm;

LL A[MAXN], R[MAXN];

LL gcd(LL a, LL b)
{
	return !b ? a : gcd(b, a%b);
}

void ex_gcd(LL a, LL b, LL &d, LL &x, LL &y)
{
	if(!b) { d = a; x = 1; y = 0;}
	else { ex_gcd(b, a%b, d, y, x); y -= x*(a/b);}
}

void read_case()
{
	lcm = 1;
	scanf("%I64d%d", &n, &m);
	for(int i = 1; i <= m; i++)
	{
		scanf("%I64d", &A[i]);
		lcm = lcm / gcd(lcm, A[i]) * A[i];
	}
	for(int i = 1; i <= m; i++) scanf("%I64d", &R[i]);
}

void solve()
{
	read_case();
	LL a, b, c, d, x, y;
	for(int i = 2; i <= m; i++)
	{
		a = A[1], b = A[i], c = R[i]-R[1];
		ex_gcd(a, b, d, x, y);
		if(c % d) { printf("0\n"); return ;}
		x *= c / d;
		LL b1 = b / d;
		x = (x%b1 + b1) % b1;
		R[1] = A[1]*x + R[1];
		A[1] = A[1] / d * A[i];
	}
	LL ans = 0;
	if(R[1] <= n) ans = 1 + (n-R[1]) / lcm;
	if(ans && R[1] == 0) ans--; //特判结果为R[1]为0时,应该是x-1. 
	printf("%I64d\n", ans);
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		solve();
	}
	return 0;
}


### HDU4453 Splay 问题的C++实现及其时间复杂度分析 HDU4453 是一个涉及Splay Tree(伸展树)的问题,要求对一系列操作进行高效处理。以下是对该问题的时间复杂度分析以及C++实现。 #### 1. Splay Tree 的基本操作时间复杂度 Splay Tree 是一种自调整二叉搜索树,其核心思想是通过旋转操作将访问过的节点移动到根节点位置,从而优化后续访问性能。Splay Tree 的基本操作包括插入、删除、查找和分裂等,这些操作的时间复杂度均为 \(O(\log n)\) 在均摊意义上[^1]。 - **插入操作**:在Splay Tree 中插入一个新节点时,首先需要找到插入位置,这一步的时间复杂度为 \(O(\log n)\)。插入后,树会通过一系列旋转操作将新节点调整到根节点位置。 - **删除操作**:删除操作需要先找到目标节点并将其旋转到根节点位置,然后调整树结构以移除该节点。这一过程的时间复杂度同样为 \(O(\log n)\)。 - **查找操作**:查找操作需要从根节点开始向下遍历,直到找到目标节点或确定目标节点不存在。查找完成后,目标节点会被旋转到根节点位置。查找操作的时间复杂度为 \(O(\log n)\)。 #### 2. HDU4453 的具体问题分析 HDU4453 要求对一个序列执行多种操作,包括插入、删除、查询排名、查询值等。以下是针对这些操作的时间复杂度分析: - **插入操作**:每次插入一个新元素时,Splay Tree 需要调整树结构以保持平衡。由于 Splay Tree 的插入操作时间复杂度为 \(O(\log n)\),因此对于 \(m\) 次插入操作,总时间复杂度为 \(O(m \log n)\)[^1]。 - **删除操作**:删除操作与插入操作类似,时间复杂度为 \(O(\log n)\)。对于 \(m\) 次删除操作,总时间复杂度为 \(O(m \log n)\)[^1]。 - **查询排名**:查询某个值的排名需要从根节点开始向下遍历,并根据左子树的大小计算排名。这一过程的时间复杂度为 \(O(\log n)\)[^1]。 - **查询值**:查询排名对应的值也需要从根节点开始向下遍历,时间复杂度同样为 \(O(\log n)\)。 #### 3. C++ 实现示例 以下是一个基于 Splay Tree 的 C++ 实现示例: ```cpp #include <bits/stdc++.h> using namespace std; struct Node { int val, size; Node *left, *right, *parent; Node(int v) : val(v), size(1), left(nullptr), right(nullptr), parent(nullptr) {} }; int getSize(Node* node) { return node ? node->size : 0; } void updateSize(Node* node) { if (node) node->size = 1 + getSize(node->left) + getSize(node->right); } void rotateRight(Node* &root, Node* y) { Node* x = y->left; y->left = x->right; if (x->right) x->right->parent = y; x->right = y; x->parent = y->parent; y->parent = x; if (x->parent) { if (x->parent->left == y) x->parent->left = x; else x->parent->right = x; } updateSize(y); updateSize(x); root = x; } void rotateLeft(Node* &root, Node* x) { Node* y = x->right; x->right = y->left; if (y->left) y->left->parent = x; y->left = x; y->parent = x->parent; x->parent = y; if (y->parent) { if (y->parent->left == x) y->parent->left = y; else y->parent->right = y; } updateSize(x); updateSize(y); root = y; } void splay(Node* &root, Node* x) { while (x->parent) { Node* p = x->parent; if (!p->parent) { if (p->left == x) rotateRight(root, p); else rotateLeft(root, p); } else { Node* pp = p->parent; if (pp->left == p) { if (p->left == x) { rotateRight(root, p); rotateRight(root, pp); } else { rotateLeft(root, x); rotateRight(root, pp); } } else { if (p->right == x) { rotateLeft(root, p); rotateLeft(root, pp); } else { rotateRight(root, x); rotateLeft(root, pp); } } } } root = x; } Node* findKth(Node* root, int k) { while (true) { int leftSize = getSize(root->left); if (k <= leftSize) { root = root->left; } else if (k == leftSize + 1) { return root; } else { k -= leftSize + 1; root = root->right; } } } Node* insert(Node* &root, int key) { if (!root) return root = new Node(key); Node* cur = root; while (true) { if (key < cur->val) { if (!cur->left) { cur->left = new Node(key); cur->left->parent = cur; break; } cur = cur->left; } else { if (!cur->right) { cur->right = new Node(key); cur->right->parent = cur; break; } cur = cur->right; } } updateSize(root); Node* newNode = key < cur->val ? cur->left : cur->right; splay(root, newNode); return root; } Node* remove(Node* &root, int key) { if (!root) return nullptr; Node* cur = root; while (cur) { if (key == cur->val) break; cur = key < cur->val ? cur->left : cur->right; } if (!cur) return root; splay(root, cur); if (!cur->left && !cur->right) { delete cur; root = nullptr; } else if (!cur->left) { root = cur->right; cur->right->parent = nullptr; delete cur; } else if (!cur->right) { root = cur->left; cur->left->parent = nullptr; delete cur; } else { Node* maxLeft = cur->left; while (maxLeft->right) maxLeft = maxLeft->right; splay(root, maxLeft); maxLeft->right = cur->right; cur->right->parent = maxLeft; delete cur; } updateSize(root); return root; } ``` #### 4. 总结 在 HDU4453 中,使用 Splay Tree 可以高效地完成插入、删除、查询排名和查询值等操作。所有这些操作的时间复杂度均为 \(O(\log n)\) 在均摊意义上[^1]。因此,对于 \(m\) 次操作,总时间复杂度为 \(O(m \log n)\)。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值