hdu 4391 Paint The Wall(根N分段哈希)

将整个区间分为sqrt(n)段小区间,每个段长度为sqrt(n),并维护每一段的统计量,这样可以在sqrt(n)时间内完成一次区间查询或更新。平衡查询和更新之间矛盾是数据结构设计时的重要考虑因素,而这种做法是经典的平衡做法,早就了解,但以前没有遇到过只能用“分段”解决的题目,因此总觉着这是迫不得已的“赖招”,也从来没有写过,昨天第一次写,小细节没注意,结果悲剧的写成每次查询O(n)了。总结一下错误:

1.对于整个区间的更新,不需要实际处理每个元素的值,只需要用一个变量标记一下即可,当整段元素更新量不一致时再更新每个元素,这样才能够保证查询时sqrt(n)的复杂度,否则就O(n)了。。。

2.如果使用map代替哈希表,如果元素不在map中不要直接查询,因为查询不存在的元素会自动插入,空间复杂度会变为n*n。

3.对于最后一段,长度可能与前边的段不同,因此需要特殊处理最后一段的长度。

鉴于java中HashMap效率很客观,自己懒得写哈希表,使用map会增加复杂度,虽然oj支持不好而且不支持下标caoz,最终还是选择了用java搞分段哈希

其它题目:

Spoj3261 Race Against Time修改某个值,查询谋取区间内小于等于k的元素个数

解法:分段+排序/Treap

spoj 861 SWAPS动态维护逆序对

解法:分段/Treap+树状数组(http://blog.csdn.net/kksleric/article/details/7929903

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.HashMap;

public class Hash {
	int maxn = 100010, maxm = 335;
	class Zone {
		HashMap<Integer, Integer> mp = new HashMap<Integer, Integer>();
		int color[] = new int[maxm], len, all;
		void init(int ln) {
			mp.clear();
			all = -1;
			len = ln;
		}
		int get(int c) {
			if (mp.containsKey(c))
				return mp.get(c);
			else
				return 0;
		}
		void set(int c) {
			all = c;
		}
		void update(int left, int right, int c) {
			if (all == c)
				return;
			if (all != -1) {
				for (int i = 1; i < left; i++)
					color[i] = all;
				for (int i = right + 1; i <= len; i++)
					color[i] = all;
			}
			for (int i = left; i <= right; i++)
				color[i] = c;
			all = -1;
			mp.clear();
			for (int i = 1; i <= len; i++)
				mp.put(color[i], get(color[i])+1);
		}

		int query(int left, int right, int c) {
			if (all == -1) {
				int sum = 0;
				for (int i = left; i <= right; i++)
					if (color[i] == c)
						sum++;
				return sum;
			} else {
				if (all == c)
					return right - left + 1;
				else
					return 0;
			}
		}
	}
	Zone zz[] = new Zone[maxm];
	int belong[] = new int[maxn], id[] = new int[maxn];
	int a[] = new int[maxn], M;
	void build(int n) {
		for (int i = 1; i * i <= n; i++)
			M = i;
		int cnt = 0, len = M;
		for (int i = 1; i <= n; i++) {
			if (len == M) {
				zz[++cnt].init(M);
				len = 0;
			}
			belong[i] = cnt;
			id[i] = ++len;
			zz[cnt].color[len] = a[i];
			zz[cnt].mp.put(a[i], zz[cnt].get(a[i]) + 1);
		}
		zz[cnt].len = len;
	}

	void update(int left, int right, int c) {
		int l = belong[left], r = belong[right];
		if (l == r) {
			zz[r].update(id[left], id[right], c);
		} else {
			zz[l].update(id[left], zz[l].len, c);
			for (int i = l + 1; i < r; i++)
				zz[i].set(c);
			zz[r].update(1, id[right], c);
		}
	}

	int query(int left, int right, int c) {
		int sum = 0;
		int l = belong[left], r = belong[right];
		if (l == r) {
			sum += zz[l].query(id[left], id[right], c);
		} else {
			sum += zz[l].query(id[left], zz[l].len, c);
			for (int i = l + 1; i < r; i++) {		
				if (zz[i].all == c)
					sum += zz[i].len;
				if(zz[i].all==-1)
					sum += zz[i].get(c);
			}
			sum += zz[r].query(1, id[right], c);
		}
		return sum;
	}
	void run() throws IOException {
		for (int i = 1; i < maxm; i++)
			zz[i] = new Zone();
		while (in.nextToken() != in.TT_EOF) {
			int n = (int) in.nval;
			int m = nextInt();
			for (int i = 1; i <= n; i++)
				a[i] = nextInt();
			build(n);
			int t, a, b, c;
			while (m-- > 0) {
				t = nextInt();
				a = nextInt() + 1;
				b = nextInt() + 1;
				c = nextInt();
				if (t == 1)
					update(a, b, c);
				else
					System.out.println(query(a, b, c));
			}
		}
	}
	StreamTokenizer in = new StreamTokenizer(new BufferedReader(
			new InputStreamReader(System.in)));

	int nextInt() throws IOException {
		in.nextToken();
		return (int) in.nval;
	}
	public static void main(String[] args) throws IOException {
		new Hash().run();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于 HDU4992 求所有原的问题,我可以给出以下解答: 1. 首先,我们需要知道什么是原。原是指模 n 意义下,所有与 n 互质的数 a 的最小正整数 k 次幂对 n 取模的值覆盖了所有与 n 互质的数。简单来说,就是如果一个数 a 是模 n 意义下的原,那么 a 的任何正整数次幂对 n 取模的值都不相同,且能覆盖所有与 n 互质的数。 2. 为了求模 n 意义下的所有原,我们需要先求出与 n 互质的数的个数 phi(n)。phi(n) 可以使用欧拉函数求出。 3. 然后,我们需要枚举模 n 意义下的所有数,判断它是否是原。具体来说,对于每个 a,我们需要判断 a 的每个小于 phi(n) 的正整数次幂对 n 取模的值是否都不相同,且能覆盖所有与 n 互质的数。如果是,那么 a 就是模 n 意义下的原。 4. 代码实现可以参考以下 Java 代码: ``` import java.util.*; public class Main { static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } static int phi(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) { n /= i; } } } if (n > 1) { res = res / n * (n - 1); } return res; } static int pow(int a, int b, int mod) { int res = 1; while (b > 0) { if ((b & 1) != 0) { res = res * a % mod; } a = a * a % mod; b >>= 1; } return res; } static boolean check(int a, int n, int phi) { for (int i = 1, j = pow(a, i, n); i <= phi; i++, j = j * a % n) { if (j == 1) { return false; } } return true; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int phi = phi(n); List<Integer> ans = new ArrayList<>(); for (int i = 1; i < n; i++) { if (gcd(i, n) == 1 && check(i, n, phi)) { ans.add(i); } } Collections.sort(ans); for (int x : ans) { System.out.print(x + " "); } System.out.println(); } } } ``` 其中,gcd 函数用于求最大公约数,phi 函数用于求欧拉函数,pow 函数用于快速幂求模,check 函数用于判断一个数是否是原。在主函数中,我们依次读入每个 n,求出 phi(n),然后枚举模 n 意义下的所有数,判断它是否是原,将所有原存入一个 List 中,最后排序输出即可。 希望我的回答能够帮到你,如果你有任何问题,欢迎随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值