济南刷题冲刺 Day2 上午

51 篇文章 0 订阅
33 篇文章 0 订阅

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 */ 
        
      
     
     
    
    
   
   
  
  


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值