赞
踩
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6287
Problem Description
小Q非常喜欢数学,但是他的口算能力非常弱。因此他找到了小T,给了小T一个长度为n的正整数序列a1,a2,...,an,要求小T抛出m个问题以训练他的口算能力。
每个问题给出三个正整数l,r,d,小Q需要通过口算快速判断al×al+1×...×ar−1×ar是不是d的倍数。
小Q迅速地回答了出来,但是小T并不知道正确答案是什么,请写一个程序帮助小T计算这些问题的正确答案。
Input
第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含两个正整数n,m(1≤n,m≤100000),分别表示序列长度以及问题个数。
第二行包含n个正整数a1,a2,...,an(1≤ai≤100000),表示序列中的每个数。
接下来m行,每行三个正整数l,r,d(1≤l≤r≤n,1≤d≤100000),表示每个问题。
Output
对于每个问题输出一行,若是倍数,输出Yes,否则输出No。
将输入的每个数分解质因数并记录,对d分解质因数并判断每个质因数在数组中是否有足够的因数。
[l, r] 中每个数相乘的结果是d的倍数,只需要 [l, r] 之间每个数的因数选择一些乘起来是 d 或 d 的倍数即可。但是暴力的储存查找会超时,所以可以通过用 vector 存因子 x 出现的所有坐标 i,然后再利用二分查找当前范围内由多少个因数。
注意,分解的时候要注意当前数是素数的情况。
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #include <cmath>
- #include <map>
- #include <cstdlib>
- #include <string>
- #include <iostream>
- #include <vector>
- #include <map>
- #include <queue>
- using namespace std;
- typedef long long LL;
- typedef pair<int, int> PII;
- const int MaxN = 1e5 + 5;
-
- vector<int> G[MaxN];
-
- int query(int l, int r, int x)
- {
- return upper_bound(G[x].begin(), G[x].end(), r) - lower_bound(G[x].begin(), G[x].end(), l);
- }
-
- bool check(int l, int r, int d)
- {
- for(int i = 2; i * i <= d; i++) {
- if(d % i == 0) { //对d分解质因数
- int cnt = 0;
- while(d % i == 0) {
- cnt++;
- d /= i;
- }
- if(query(l, r, i) < cnt) return 0;
- }
- }
- if(d > 1 && query(l, r, d) < 1) return 0; //如果当前数是素数
- return 1;
- }
-
- int main ()
- {
- int t; scanf("%d", &t);
- while(t--) {
- for(int i = 1; i <= MaxN; i++) G[i].clear();
- int n, m;
- scanf("%d %d", &n, &m);
- for(int i = 1; i <= n; i++) {
- int x; scanf("%d", &x);
- for(int j = 2; j * j <= x; j++) { //对数组中的数分解质因数
- while(x % j == 0) {
- x /= j;
- G[j].push_back(i); //对于每次当前的质因数都存储坐标i
- }
- }
- if(x > 1) G[x].push_back(i); //当前数是素数
- }
- while(m--) {
- int l, r, d;
- scanf("%d %d %d", &l, &r, &d);
- if(check(l, r, d)) printf("Yes\n");
- else printf("No\n");
- }
- }
- return 0;
- }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6288
Problem Description
著名出题人小Q出过非常多的题目,在这个漫长的过程中他发现,确定题目的数据范围是非常痛苦的一件事。
每当思考完一道题目的时间效率,小Q就需要结合时限以及评测机配置来设置合理的数据范围。
因为确定数据范围是一件痛苦的事,小Q出了非常多的题目之后,都没有它们设置数据范围。对于一道题目,小Q会告诉你他的算法的时间复杂度为O(nalogbn),且蕴含在这个大O记号下的常数为1。同时,小Q还会告诉你评测机在规定时限内可以执行k条指令。小Q认为只要na(⌈log2n⌉)b不超过k,那么就是合理的数据范围。其中,⌈x⌉表示最小的不小于x的正整数,即x上取整。
自然,小Q希望题目的数据范围n越大越好,他希望你写一个程序帮助他设置最大的数据范围。
Input
第一行包含一个正整数T(1≤T≤1000),表示测试数据的组数。
每组数据包含一行三个正整数a,b,k(1≤a,b≤10,106≤k≤1018),分别描述时间复杂度以及允许的指令数。
Output
对于每组数据,输出一行一个正整数n,即最大可能的n。
给出a、b、k,对于公式
1 ≤ a, b ≤ 10
1e6 ≤ k ≤ 1e18
二分查找可行解。
把公式分为
需要注意的两点是:
- #include <cstdio>
- #include <cstring>
- #include <string>
- #include <cmath>
- #include <cstdlib>
- #include <ctime>
- #include <iostream>
- #include <algorithm>
- #include <vector>
- #include <queue>
- #include <stack>
- #include <set>
- #include <map>
- #define fi first
- #define se second
- #define mst(a, b) memset(a, b, sizeof(a))
- using namespace std;
- typedef long long LL;
- typedef pair<int, int> PII;
- const int INF = 0x3f3f3f3f;
- const double eps = 1e-9;
- const int Mod = 1e9 + 7;
- const int MaxN = 1e5 + 5;
-
- int a, b;
- LL k;
-
- LL log2(LL mid)
- {
- for(int i = 0; i <= 64; i++) {
- if(pow(2LL, i) >= mid) return i;
- }
- }
-
- bool check(LL mid)
- {
- LL pre = 1LL;
- for(int i = 1; i <= a; i++) { //判断前面部分
- if(pre <= k / mid) pre *= mid; //防止乘法溢出
- else return false; //当前的结果大于k说明不合法
- }
- LL base = log2(mid);
- LL suf = 1LL;
- if(suf == 0) return true; //否则会在下面的除法中出现RE
- for(int i = 1; i <= b; i++) { //判断后面部分
- if(suf <= k / mid) suf *= base;
- else return false;
- }
- if(pre <= k / suf) return true; //将两部分合起来判断一次
- return false;
- }
-
- int main()
- {
- //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
-
- int t; scanf("%d", &t);
- while(t--) {
- scanf("%d %d %lld", &a, &b, &k);
- LL l = 0LL, r = 1e18, ans = 0LL;
- while(l <= r) {
- LL mid = (l + r) / 2;
- if(check(mid)) l = mid + 1, ans = mid;
- else r = mid - 1;
- }
- cout << ans << endl;
- }
-
- return 0;
- }
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6289
Problem Description
小Q最近迷上了一款寻宝游戏,这款游戏中每局都会生成一个n×m的网格地图,从上往下依次编号为第1行到第n行,从左往右依次编号为第1列到第m列。每个格子上都有不同数量的金币,第i行第j列的格子上的金币数量为ai,j。
小Q一开始位于(1,1),每次他可以往右或者往下走,每当他经过某个格子时,他就可以拿走这个格子上的所有金币。小Q不能走出这个地图,当小Q不能再行动时,游戏结束。显然当且仅当小Q位于(n,m)时,游戏才会结束。
一轮游戏的得分为这一轮中收集到的金币总量,而在游戏开始前,因为小Q是超级VIP用户,所以他有k次机会交换某两个格子中的金币数。这k次机会不一定要用完,请写一个程序帮助小Q在一轮内拿到尽可能多的金币。
Input
第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含三个整数n,m,k(2≤n,m≤50,0≤k≤20),分别表示地图的长宽以及交换的次数。
接下来n行,每行m个整数ai,j(0≤ai,j≤106),依次表示每个格子中金币的数量。
Output
对于每组数据,输出一行一个整数,即能收集到的金币数量的最大可能值。
对于 n*m 的矩阵每个点都有一个权值。从 (1, 1) 开始每次只能向下或向右走,求到达 (n, m) 时可以获得的最大值,其中你有k次交换机会交换任意两点上的权值。
假设已经选定了一条路线,那么不考虑具体交换方案,考虑选定一个 t(t ≤ k),经过的格子里要有 t 个格子的权值不计入得分,而不经过的格子里要有 t 个格子的权值计入总分。那么每一种交换方案都可以对应这样一个转化。
设
格子一定按照权值从大到小贪心选择。
最终答案即为
时间复杂度O(
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。