Price List
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5804解题思路:
中文题目:
问题描述
在Byteland一共有n家商店,编号依次为1到n。每家商店只会卖一种物品,其中第i家商店的物品单价为vi。 Byteasar每天都会进行一次购物,他会在每家商店购买最多一件物品,当然他也可以选择什么都不买。回家之后,Byteasar会把这一天购物所花的钱的总数记录在账本上。 Byteasar的数学不好,他可能会把花的钱记少,也可能记多。Byteasar并不介意记少,因为这样看上去显得自己没花很多钱。 请写一个程序,帮助Byteasar判断每条记录是否一定记多了。
输入描述
输入的第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。 对于每组数据,第一行包含两个正整数n,m(1≤n,m≤100000),表示商店的个数和记录的个数。 第二行包含n个正整数vi(1≤vi≤100000),依次表示每家商店的物品的单价。 接下来m行,每行包含一个整数q(0≤q≤1018),表示一条记录。
输出描述
对于每组数据,输出一行m个字符,依次回答每个询问。如果一定记多了,请输出'1',否则输出'0'。
输入样例
1 3 3 2 5 4 1 7 10000
输出样例
001算法思想:
求出所有数的和sum,如果q>sum那么肯定记多了。
时间复杂度O(n)。
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
int main(){
int T;
scanf("%d",&T);
while(T--){
int x,n,m;
scanf("%d%d",&n,&m);
ll sum = 0,tmp;
for(int i = 0; i < n; ++i){
scanf("%d",&x);
sum += x;
}
for(int i = 0; i < m;++i){
scanf("%lld",&tmp);
if(tmp <= sum)
putchar('0');
else
putchar('1');
}
puts("");
}
return 0;
}
NanoApe Loves Sequence
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5805解题思路:
中文题目:
问题描述
退役狗 NanoApe 滚回去学文化课啦!
在数学课上,NanoApe 心痒痒又玩起了数列。他在纸上随便写了一个长度为 n 的数列,他又根据心情随便删了一个数,这样他得到了一个新的数列,然后他计算出了所有相邻两数的差的绝对值的最大值。
他当然知道这个最大值会随着他删了的数改变而改变,所以他想知道假如全部数被删除的概率是相等的话,差的绝对值的最大值的期望是多少。
输入描述
第一行为一个正整数 T,表示数据组数。 每组数据的第一行为一个整数 n。 第二行为 n 个整数 Ai,表示这个数列。 1≤T≤10, 3≤n≤100000, 1≤Ai≤109
输出描述
对于每组数据输出一行一个数表示答案。
为防止精度误差,你需要输出答案乘上 n 后的值。
输入样例
1 4 1 2 3 4
输出样例
6
算法思想:
求出前i个数里相邻差值的最大值fi,i到n里相邻差值的最大值gi,那么ans=∑i=1nmax(∣Ai−1−Ai+1∣,fi−1,gi+1)。
时间复杂度O(n)。
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 100005;
int a[N],l[N],r[N];
int main () {
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i = 1; i <= n; ++i){
scanf ("%d",&a[i]);
}
l[1] = r[n] = 0;
for(int i = 2; i <= n; ++i){
l[i] = max(l[i-1],abs(a[i]-a[i - 1]));
}
for(int i = n - 1; i >= 1; --i){
r[i] = max(r[i + 1],abs(a[i]-a[i + 1]));
}
ll ans = r[2]+l[n - 1];
for(int i = 2; i < n; ++i){
ans += max(abs(a[i-1]-a[i+1]),max(l[i-1],r[i+1]));
}
printf("%lld\n",ans);
}
}
NanoApe Loves Sequence Ⅱ
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5806解题思路:
中文题目:
问题描述
退役狗 NanoApe 滚回去学文化课啦! 在数学课上,NanoApe 心痒痒又玩起了数列。他在纸上随便写了一个长度为 n 的数列,他又根据心情写下了一个数 m。 他想知道这个数列中有多少个区间里的第 k 大的数不小于 m,当然首先这个区间必须至少要有 k 个数啦。
输入描述
第一行为一个正整数 T,表示数据组数。 每组数据的第一行为三个整数 n,m,k。 第二行为 n 个整数 Ai,表示这个数列。 1≤T≤10, 2≤n≤200000, 1≤k≤n/2, 1≤m,Ai≤109
输出描述
对于每组数据输出一行一个数表示答案。
输入样例
1 7 4 2 4 2 7 7 6 5 1
输出样例
18
算法思想:
将不小于m的数看作1,剩下的数看作0,那么只要区间内1的个数不小于k则可行,枚举左端点,右端点可以通过two-pointer求出。
时间复杂度O(n)。
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 200005;
int a[N];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for(int i = 1; i <= n; ++i)
scanf("%d",&a[i]);
int num = 0,r = 0;
ll ans = 0;
for(int i = 1; i <= n; ++i){
while(num < k && r < n){
r++;
num += (a[r]>=m);
}
if(num < k)
break;
ans += n-r+1;
num -= (a[i]>=m);
}
printf("%lld\n",ans);
}
return 0;
}
Keep In Touch
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=5807解题思路:
中文题目:
问题描述
在Byteland一共有n个城市,编号依次为1到n,同时有m条单向道路连接着这些城市,其中第i条道路的起点为ui,终点为vi(1≤ui<vi≤n)。 特工团队一共有3名成员:007,008,以及009,他们将要执行q次秘密任务。 在每次任务中,三人可能会处于三个不同的城市,他们互相之间通过对讲机保持联络。编号为i的城市的无线电频为wi,如果两个城市的无线电频差值的绝对值不超过K,那么无线电就可以接通。三个特工每个时刻必须要选择一条道路,走到下一个城市,每条道路都只需要花费1单位时间。 他们可以选择在任意城市终止任务,甚至可以在起点就终止任务,但不允许在道路上终止任务。现在他们想知道,对于每次任务,给定三个人的起始位置,有多少种可能的合法行动方案,使得行动过程中任意在城市的时刻,他们都可以两两联络? 两个方案被视作不同当且仅当至少存在一个人在某一时刻所在的城市不同。 注意:3个特工必须同时结束任务。
输入描述
输入的第一行包含一个正整数T(1≤T≤10),表示测试数据的组数。 对于每组数据,第一行包含四个整数n(1≤n≤50),m(0≤m≤2n(n−1)),K(0≤K≤109),q(1≤q≤125000),表示城市数,道路数,允许的差值上限以及任务个数。 第二行包含n个正整数wi(1≤wi≤109),依次表示每个城市的无线电频。 接下来m行,每行包含两个正整数ui,vi(1≤ui<vi≤n),表示一条单向道路,数据保证没有重边。 接下来q行,每行包含三个正整数x,y,z(1≤x,y,z≤n),表示一次任务中三个人的起始位置。数据保证在起始位置三个人可以两两联络。
输出描述
对于每组数据,输出q行,对于每个任务输出方案数。由于答案可能很大,请对998244353取模。
输入样例
1 4 4 2 10 8 8 4 1 1 3 1 4 2 3 2 4 1 1 1 1 1 2 1 2 1 1 2 2 2 1 1 2 1 2 2 2 1 2 2 2 3 3 3 4 4 4
输出样例
3 3 3 3 3 3 3 3 1 1
算法思想:
考虑dp,设f[i][j][k]表示三个人分别在i,j,k时的方案数,直接转移是O(n6)的。
于是考虑加维,设f[i][j][k][now]表示三个人分别在i,j,k时,目前准备走now这个人的方案数,那么转移复杂度就降低到了O(n4)。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 55;
const int MOD = 998244353;
int w[N],a[N][N];
int f[N][N][N],g[N][N][N],h[N][N][N];
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m,K,q;
int x,y,z;
scanf("%d%d%d%d",&n,&m,&K,&q);
for(int i = 1; i <= n; ++i)
scanf("%d",&w[i]);
memset(a,0,sizeof(a));
while(m--){
scanf("%d%d",&x,&y);
a[y][x] = 1;
}
for(int i = n; i >= 1; --i){
for(int j = n; j >= 1; --j){
for(int k = n; k >= 1; --k){
f[i][j][k] = 1;
g[i][j][k] = h[i][j][k] = 0;
for(int t = 1; t <= n; ++t){
if(a[t][i])
f[i][j][k] = (f[i][j][k]+h[t][j][k])%MOD;
}
for(int t = 1; t <= n; ++t){
if(a[t][j])
h[i][j][k] = (h[i][j][k]+g[i][t][k])%MOD;
}
for(int t = 1; t <= n; ++t){
if(a[t][k])
g[i][j][k] = (g[i][j][k]+f[i][j][t])%MOD;
}
if(abs(w[i]-w[j]) > K || abs(w[i]-w[k]) > K || abs(w[j]-w[k]) > K)
f[i][j][k] = 0;
}
}
}
while(q--){
scanf("%d%d%d",&x,&y,&z);
printf("%d\n",f[x][y][z]);
}
}
return 0;
}