8月3日到8月10日笔记总结兼补上周

前言

事实证明体力与饮食的重要性,这周被外卖干的快吐了。下周开始锻炼吧。(狗头保命)

A-海底高铁

Description

该铁路经过 N 个城市,每个城市都有一个站。不过,由于各个城市之间不能协调好,于是乘车每经过两个相邻的城市之间(方向不限),必须单独购买这一小段的车票。第 i 段铁路连接了城市 i 和城市 i+1(1≤i<N)。如果搭乘的比较远,需要购买多张车票。第 i 段铁路购买纸质单程票需要 Ai​ 博艾元。

虽然一些事情没有协调好,各段铁路公司也为了方便乘客,推出了 IC 卡。对于第 i 段铁路,需要花 Ci​ 博艾元的工本费购买一张 IC 卡,然后乘坐这段铁路一次就只要扣Bi​(Bi​<Ai​) 元。IC 卡可以提前购买,有钱就可以从网上买得到,而不需要亲自去对应的城市购买。工本费不能退,也不能购买车票。每张卡都可以充值任意数额。对于第 i 段铁路的 IC 卡,无法乘坐别的铁路的车。

Uim 现在需要出差,要去 M 个城市,从城市 P1​ 出发分别按照P1​,P2​,P3​,⋯,PM​ 的顺序访问各个城市,可能会多次访问一个城市,且相邻访问的城市位置不一定相邻,而且不会是同一个城市。

现在他希望知道,出差结束后,至少会花掉多少的钱,包括购买纸质车票、买卡和充值的总费用。

Input

第一行两个整数,N,M。

接下来一行,M 个数字,表示 Pi​。

接下来N−1 行,表示第 i 段铁路的 Ai​,Bi​,Ci​。

Output

一个整数,表示最少花费

Sample 1

InputcopyOutputcopy
9 10
3 1 4 1 5 9 2 6 5 3
200 100 50
300 299 100
500 200 500
345 234 123
100 50 100
600 100 1
450 400 80
2 1 10
6394

Hint

22 到 33 以及 88 到 99 买票,其余买卡。

对于 30%30% 数据 M=2。

对于另外 30%30% 数据 N≤1000,M≤1000。

对于 100%100% 的数据 M,N≤10^5,Ai​,Bi​,Ci​≤10^5。

详解

#include<bits/stdc++.h>
using namespace std;
int v[100005],s[100005];
long long a[100005],b[100005],c[100005]; 
int main()
{ 
    int n,m,i;
    cin>>n>>m;
    for(i=1;i<=m;i++){
     cin>>v[i];	
	}
	for(i=1;i<n;i++){
     	cin>>a[i]>>b[i]>>c[i];
	}
	for(i=1;i<m;i++){
     	s[min(v[i],v[i+1])]++;
     	s[max(v[i],v[i+1])]--;
	}
	for(i=1;i<n;i++){
     	s[i]+=s[i-1];
	}
	long long sum=0;
	for(i=1;i<n;i++){
     	sum+=min(a[i]*s[i],b[i]*s[i]+c[i]);
	}
	cout<<sum;
}

技巧

1、按大小(前后)顺序前缀和;

PS :关注某部分多次重复加减;

B-学生分组

Description

有 n 组学生,给出初始时每组中的学生个数,再给出每组学生人数的上界 R 和下界 L (L≤R),每次你可以在某组中选出一个学生把他安排到另外一组中,问最少要多少次才可以使 N 组学生的人数都在 [L,R] 中。

Input

第一行一个整数 n,表示学生组数;

第二行 n 个整数,表示每组的学生个数;

第三行两个整数 L,R,表示下界和上界。

Output

一个数,表示最少的交换次数,如果不能满足题目条件输出 −1。

Sample 1

InputcopyOutputcopy
2
10 20
10 15
5

Hint

数据范围及约定

对于全部数据,保证 1≤n≤50。

详解

#include<bits/stdc++.h>
using namespace std;
int a[55];
int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); 	
	    int n,i;
		double sum=0;	
		 cin>>n;
		for(i=1;i<=n;i++){
		cin>>a[i];sum+=a[i];
		} 
		int L,R;
		cin>>L>>R;
		if(sum/n*1.0<L||1.0*sum/n>R){
			cout<<"-1"; return 0;
		}  
		int l=0,r=0;
		for(i=1;i<=n;i++){
		 if(a[i]<L){
		    l+=(L-a[i]);
		 }    
		 else if(a[i]>R){
		    r+=a[i]-R;
		 }
		}
		if(l>r) r+=l-r;
		cout<<r;
}
		

技巧

1. 分别算出左移右移次数,输出多的;

C-最大正方形

Description

在一个 n×m 的只包含 0 和 1 的矩阵里找出一个不包含 0 的最大正方形,输出边长。

Input

输入文件第一行为两个整数 n,m(1≤n,m≤100),接下来 n 行,每行 m 个数字,用空格隔开,0 或 1。

Output

一个整数,最大正方形的边长。

Sample 1

InputcopyOutputcopy
4 4
0 1 1 1
1 1 1 0
0 1 1 0
1 1 0 1
2

详解

#include<bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); 	
	    long long n,m,i,j,a[105][105],s[105][105];	
		cin>>n>>m;
		for(i=1;i<=n;i++){
		 	for(j=1;j<=m;j++){
		 	  cin>>a[i][j];
		 	s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j]; 
		    } 
		}
		int size=min(n,m),ans=0;
		for(i=1;i<=n;i++){
		 	for(j=1;j<=m;j++){
		 	  for(int l=1;l<=size;l++){
		 	  int x=i+l-1,y=j+l-1;
		 	  if(x>n||y>m||s[x][y]-s[x][j-1]-s[i-1][y]+s[i-1][j-1]!=l*l)
		 	  break;
		 	  if(ans<l)ans=l;
		    } 
		   }
        }
        cout<<ans;
}
		

D-K倍区间

Description

给定一个长度为 N 的数列,A1​,A2​,⋯AN​,如果其中一段连续的子序列Ai​,Ai+1​,⋯Aj​(i≤j) 之和是 K 的倍数,我们就称这个区间[i,j] 是 K 倍区间。

你能求出数列中总共有多少个 K 倍区间吗?

Input

第一行包含两个整数 N 和MATH:0(1≤Ai​≤10^5)。

Output

输出一个整数,代表 K 倍区间的数目。

Sample 1

InputcopyOutputcopy
5 2
1  
2  
3  
4  
5  
6

Hint

时限 2 秒, 256M。蓝桥杯 2017 年第八届

详解

​
#include<bits/stdc++.h>
using namespace std;
int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); 	
	    long long n,k,i,j,a[100005],s[100005];	
		cin>>n>>k;
		s[0]=0;
		for(i=1;i<=n;i++){
		 	cin>>a[i];
		 	s[i]=s[i-1]+a[i]; 
		}
		long long sum=0;
		map<long long,long long> m;
		for(i=1;i<=n;i++){
		 	sum+=m[s[i]%k];
			m[s[i]%k]++;  
		}
		cout<<sum+m[0];
	
}
		

​

E-一元三次方程求解

Description

有形如:a*x^3+b*x^2+c*x+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在 −100 至 100 之间),且根与根之差的绝对值 ≥1≥1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 22 位。

提示:记方程f(x)=0,若存在 22 个数 x1​ 和 x2​,且x1​<x2​,f(x1​)×f(x2​)<0,则在 (x1​,x2​) 之间一定有一个根。

Input

一行,4个实数 a,b,c,d。

Output

一行,33 个实根,从小到大输出,并精确到小数点后 22 位。

Sample 1

InputcopyOutputcopy
1 -5 -4 20
-2.00 2.00 5.00

Hint

【题目来源】

NOIP 2001 提高组第一题

详解

#include<bits/stdc++.h>
using namespace std;
double  a,b,c,d,i;
double f( double i){
   return (a*i*i*i+b*i*i+c*i+d);
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); 	
	  	
		 cin>>a>>b>>c>>d;
		 int count=0;
		for(i=-100;i<=100;i++){
		    double l=i,r=i+1;
		    double x1=f(l);
		    double x2=f(r);
		    if(!x1){
		    	printf("%.2lf ",l);
				count++;
			}
		    if(x1*x2<0){
		    	  double mid;
		    	  while(r-l>=0.001){
		    	  	mid=(l+r)/2;
		    	  	if(f(r)*f(mid)<=0) l=mid;
		    	  	else r=mid;
				  }
		    	  printf("%.2lf ",r);
		    	  count++;
			}
			if(count==3) break;
			
		} 
}
		

F-银行贷款

Description

当一个人从银行贷款后,在一段时间内他(她)将不得不每月偿还固定的分期付款。这个问题要求计算出贷款者向银行支付的利率。假设利率按月累计。

Input

三个用空格隔开的正整数。

第一个整数表示贷款的原值 w0​,第二个整数表示每月支付的分期付款金额 w,第三个整数表示分期付款还清贷款所需的总月数 m。

Output

一个实数,表示该贷款的月利率(用百分数表示),四舍五入精确到0.1%。

数据保证答案不超过300.0%。

Sample 1

InputcopyOutputcopy
1000 100 12
2.9

Hint

数据保证,1≤w0​,w≤2^31−1,1≤m≤3000。

详解

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
bool f( double a){
	double sum=n;
	for(int i=1;i<=k;i++){
		sum+=sum*a;
		sum-=m;
	}
	if(sum<=0) return true;
	else return false;
}
int main()
{
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr); 
		cin>>n>>m>>k;
		double l=0,r=500;
		while(r-l>0.01){
			double mid=(r+l)/2;
			if(f(mid/100)) l=mid;
			else r=mid;
		}
		printf("%.1lf",l);
}
		

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值