P104
zhx
题目名称 | 遭遇 | 都市 | 街灯 |
名称 | meet | city | light |
输入 | meet.in | city.in | light.in |
输出 | meet.out | city.out | light.out |
每个测试点时限 | 1s | 1s | 1.5s |
内存限制 | 256MB | 256MB | 256MB |
测试点数目 | 10 | 10 | 10 |
每个测试点分值 | 10 | 10 | 10 |
是否有部分分 | 无 | 无 | 无 |
题目类型 | 传统 | 传统 | 传统 |
注意事项(请务必仔细阅读):
遭遇
【问题描述】
你是能看到第一题的friends呢。
——hja
N座楼房,立于城中。
第i座楼,高度hi。
你需要一开始选择一座楼,开始跳楼。在第i座楼准备跳楼需要ci的花费。每次可以跳到任何一个还没有跳过的楼上去。但跳楼是有代价的,每次跳到另外一座楼的代价是两座楼高度的差的绝对值,最后一次从楼上跳到地面上不需要代价(只能跳到地上一次)。为在代价不超过T的情况下,最多跳几次楼。(一座楼只能跳一次,且每次跳楼都要计算准备的花费)
【输入格式】
第一行一个整数N,代表楼的数量。
接下来一行N个整数代表ci。
接下来一行N个整数代表hi。
最后一行一个整数T。
【输出格式】
一行一个整数代表答案。
【样例输入】
4
3 5 4 11
2 1 3 1
17
【样例输出】
3
【样例解释】
从1号楼跳到2号楼再跳到3号楼是一种可行的方案。
【数据范围与规定】
对于30%的数据,1≤N≤5。
对于另外20%的数据,所有hi相同。
对于另外20%的数据,ci=0。
对于100%的数据,1≤N≤50,1≤ci,hi≤10^6,1≤T≤10^7。
#include
#include
#include
#include
#define N 51
using namespace std;
int dp[N][N];
struct Node { int c,h; }p[N];
inline void read(int &x) {
x = 0; register char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
}
//dp[i][j] 当前在i 跳了j次
inline bool cmp(Node p,Node q) { return p.h < q.h; }
int main(int argc,char *argv[]) {
freopen("meet.in","r",stdin);
freopen("meet.out","w",stdout);
int n; read(n);
for(int i=1; i<=n; ++i) read(p[i].c);
for(int i=1; i<=n; ++i) read(p[i].h);
sort(p + 1, p + n + 1,cmp);
memset(dp,127/3,sizeof(dp));
for(int i=1; i<=n; ++i) dp[i][0] = p[i].c;
for(int j=1; j<=n; ++j)//跳了 j 次
for(int i=1; i<=n; ++i) {
for(int k=1; k
=0; --j) for(int i=n; i>j; --i) if(dp[i][j] <= T) { printf("%d\n",j + 1); fclose(stdin); fclose(stdout); return 0; } }
都市
【问题描述】
你是能看到第二题的friends呢。
——laekov
塔立于都市,攀登上塔,能够到达更远的地方。但是上塔,需要破解谜题。仍然有N个数,但并不给你,而是给了你N×N-12个数,代表它们两两的和。那么,这N个数是多少呢?
【输入格式】
一行一个整数N。
接下来一行N×N-12个数,代表两两之和。
【输出格式】
第一行一个整数s代表解的个数。
接下来s行,每行N个数代表一组解,数从小到大排列。解的顺序按照字典序从大到小排列。
【样例输入1】
4
3 5 4 7 6 5
【样例输出1】
1
1 2 3 4
【样例输入2】
4
11 17 21 12 20 15
【样例输出2】
2
4 7 8 13
3 8 9 12
【数据范围与规定】
对于30%的数据,1≤N≤5,N个数均不超过10。
对于60%的数据,1≤N≤50,N个数均不超过100。
对于100%的数据,1≤N≤300,N个数均不超过10^8。
设给出的数是b1,b2,……
解为a1,a2……
那么可以得到 b1=a1+a2,b2=a1+a3
如果再知道 a2+a3=X,就可以解出a1,a2,a3
在b中把b1 b2 X 删去
剩下的最小的一定是 a1+a4,解出a4
再把a2+a4 ,a2+a4 删去,剩下的最小的一定是a1+a5
以此类推,解出所有的a
#include
#include
#include
#include
using namespace std;
int n,m,tot;
#define N 302
int b[N*N];
int Ans[N*N][N],t[N];
bool use[N*N];
void read(int &x){
x=0; register char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) x = x * 10 + c - '0',c = getchar();
}
void work(int x){
if((b[1] + b[2] + b[x]) & 1) return;
t[2] = b[1] - b[2] + b[x] >> 1;
t[1] = b[1] - t[2];
t[3] = b[2] - t[1];
memset(use,false,sizeof(use));
use[1] = use[2] = use[x] = true;
int r,pos;
for(int i=3,k=4; i<=m; ++i){
if(use[i]) continue;
t[k] = b[i] - t[1];
for(int j=1; j
1 && b[i] == b[i-1]) continue; work(i); } printf("%d\n",tot); for(int i=1; i<=tot; ++i) { for(int j=1; j<=n; ++j) printf("%d ",Ans[i][j]); printf("\n"); } }
街灯
【问题描述】
你是能看到第三题的friends呢。
——aoao
街上的街灯亮起,指引向着远方的路。每个街灯上都有一个数,每次询问,第l个街灯到第r个街灯上的数模p等于v的有几个。
【输入格式】
第一行两个数N,M,代表街灯的个数和询问的个数。
接下来一行N个数,代表街灯上的数。
接下来M行,每行四个数l,r,p,v代表一组询问。
【输出格式】
对于每次询问,输出一行代表答案。
【样例输入】
5 2
1 5 2 3 7
1 3 2 1
2 5 3 0
【样例输出】
2
1
【数据规模与约定】
对于30%的数据,1≤N,M≤10^3。
对于另外30%的数据,每次询问的p一样。
对于100%的数据,1≤N,M≤10^5,街灯上的数不超过10^4,1≤p≤10^9。
分析:
分块
因为街灯上的数不超过1e4,所以p最多有1e4个
用vector[i][j] 存下%i=j 的数的位置 i<=100
当p<=100 时,直接在vector[p][v] 里二分在区间[l,r]内的最左位置和最右位置
再用一个vector[i] 存下所有的街灯数位i的位置
当p>100 时,%p=v 的数 有v,v+p,v+2p……
直接枚举这些数,最多100个,在vector[i] 里 二分 在区间[l,r]内的最左位置和最右位置
#include
#include
#include
#include
#define N 100001
using namespace std;
int a[N];
vector
V1[101][101]; vector
V2[N]; inline void read(int &x) { x = 0; register char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) x = x * 10 + c - '0', c = getchar(); } int main(int argc,char *argv[]){ freopen("light.in","r",stdin); freopen("light.out","w",stdout); int n,m; read(n),read(m); for(int i=1; i<=n; ++i) read(a[i]); for(int i=1; i<=n; ++i) V2[a[i]].push_back(i); for(int i=1; i<=100; ++i) for(int j=1; j<=n; ++j) V1[i][a[j] % i].push_back(j); int l,r,p,v,L,R,Mid,Ans1,pos,tot,Ans2; while(m--) { read(l),read(r),read(p),read(v); Ans1 = Ans2 = -1; if(p <= 100) { L = 0, R = V1[p][v].size() - 1; while(L <= R) { Mid = L + R >> 1; if(V1[p][v][Mid] >= l) Ans1 = Mid, R = Mid - 1; else L = Mid + 1; } if(Ans1 == -1) { puts("0"); continue; } L = Ans1, R = V1[p][v].size() - 1; while(L <= R) { Mid = L + R >> 1; if(V1[p][v][Mid] <= r) Ans2 = Mid, L = Mid + 1; else R = Mid - 1; } if(Ans2 == -1) { puts("0"); continue; } printf("%d\n",Ans2 - Ans1 + 1); } else { pos = v,tot = 0; while(pos <= 10000){ L = 0,R = V2[pos].size() - 1; Ans1 = Ans2 = -1; while(L <= R) { Mid = L + R >> 1; if(V2[pos][Mid] >= l) Ans1 = Mid,R = Mid - 1; else L = Mid + 1; } if(Ans1 == -1) { pos += p; continue; } L = Ans1,R = V2[pos].size() - 1; while(L <= R) { Mid = L + R >> 1; if(V2[pos][Mid] <= r) Ans2 = Mid,L = Mid + 1; else R = Mid - 1; } if(Ans2 == -1) { pos += p; continue; } tot += Ans2 - Ans1 + 1; pos += p; } printf("%d\n",tot); } } fclose(stdin); fclose(stdout); return 0; } /* 5 2 1 5 2 3 7 1 3 2 1 2 5 3 0 */