第三周+周赛补

7-1 区间选点

给定 N 个闭区间 [ai​,bi​], 请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。
输出选择的点的最小数量。
位于区间端点上的点也算作区间内。

输入格式:

第一行包含一个整数 N , 表示区间数。
接下来 N 行,每行包含两个整数 ai​,bi​,表示一个区间的两个端点。
1≤N≤105,
−109≤ai​≤bi​≤109

输出格式:

输出一个整数,表示所需的点的最小数量。

输入样例:

3
-1 1
2 4
3 5

输出样例:

2
#include<bits/stdc++.h>
using namespace std;
bool cmp(pair<int, int>a1, pair<int, int>a2) {
	if (a1.first == a2.first)return a1.second < a2.second;
	return a1.first < a2.first;
}
int main() {
	int n;
	cin >> n;
	pair<int, int>temp;
	vector<pair<int, int>>ans;
	for (int i = 0; i < n; i++) {
		cin >> temp.first >> temp.second;
		ans.push_back(temp);
	}
	sort(ans.begin(), ans.end(), cmp);
	int count = 1; temp = ans[0];
	for (int i=1;i<n;i++) {
		if (ans[i].first > temp.second) {
			count++;
			temp = ans[i];
		}
		if (ans[i].second < temp.second) {
			temp.second = ans[i].second;
		}
		temp.first = ans[i].first;
	}
	cout << count << endl;
	return 0;
}

使用贪心排序求解

7-2 添加括号

现在给出一个表达式,形如 a1​/a2​/a3​/.../an​。
如果直接计算,就是一个个除过去,比如 1/2/1/4=1/8。
然而小A看到一个分数感觉很不舒服,希望通过添加一些括号使其变成一个整数。一种可行的办法是 (1/2)/(1/4)=2 。
现在给出这个表达式,求问是否可以通过添加一些括号改变运算顺序使其成为一个整数。

输入格式

一个测试点中会有多个表达式。
第一行 t ,表示表达式数量。
对于每个表达式,第一行是 n,第二行 n 个数,第 i 个数表示 ai​。
2≤n≤10000,1≤t≤100,1≤ai​≤231−1。

输出格式

输出 t 行。
对于每个表达式,如果可以通过添加括号改变顺序使其变成整数,那么输出 Yes,否则输出 No

样例输入:

2
4
1 2 1 4
5
6 5 7 9 12

样例输出:

Yes
No
#include<bits/stdc++.h>
using namespace std;
bool kuohao(int n) {
	int m, temp;
	cin >> m >> temp;
	temp = temp / (__gcd(temp, m));
	for (int i=2;i<n;i++) {
		cin >> m;
		temp = temp / (__gcd(temp, m));
	}
	return temp==1;
}
int main() {
	int n;
	cin >> n;
	int temp;
	for (int i=0;i<n;i++) {
		cin >> temp;
		if (kuohao(temp)) {
			cout << "Yes" << endl;
		}
		else cout << "No" << endl;
	}
	
	return 0;
}

找与第二个的因子能让最后除第二个为整数便可

7-3 山头狙击战

题目描述

小明为了掩护大部队,单枪匹马同敌人周旋,后来被敌人包围在某山头……等等,为什么怎么听怎么像狼牙山五壮士!不过不用着急,这次小明携带了足够的弹药,完全可以将涌上来的敌人一个一个干掉。小明是个神枪手,只要他的枪膛中有子弹,他就能将在他射程m(用从敌人位置到山头的直线距离算)以内的一个敌人瞬间射杀。但如果在射程内没有敌人,出于节约子弹考虑和面子问题,小明会等待敌人靠近然后射击。
正当小明为自己的强大而自我膨胀时,他忽然发现了一个致命的失误:他携带的枪是单发枪,每射出一发子弹都必须花k秒钟的时间装子弹。而凶残的敌人才不会花时间等你换子弹呢。他们始终在以1m/s的速度接近山头。而如果在一个敌人到达山头时小明无法将他击毙,那么我们可怜的小明就将牺牲在敌人的刺刀下。现在小明用心灵感应向你发出求助:要保住自己的性命并且歼灭所有敌人,小明最多只能用多少时间给枪装上一发子弹?
说明:假设一开始小明的枪中就有一发子弹,并且一旦确定一个装弹时间,小明始终会用这个时间完成子弹的装卸。希望你能帮助小明脱离险境。

输入格式

每组输入数据,第一行有两个整数n和m,(2≤n≤100,000; 1≤m≤10,000,000)n代表敌人个数,m代表小明的射程。
接下来有n行,每行一个整数mi,(1≤mi≤10,000,000),代表每个敌人一开始相对山头的距离(单位为米)。

输出格式

每组输出数据仅有一个整数,代表小明的换弹时间(单位为秒)。

样例输入

6 100
236
120
120
120
120
120

样例输出

25
#include<bits/stdc++.h>
using namespace std;
vector<int>ren;
bool jianyan(int k,int m) {
	int now = 0;
	for (int i=0;i<ren.size();i++) {
		if (ren[i] > m+now) {
			now = (ren[i] - m);
			now += k;
		}
		else {
			if (now > ren[i])return false;
			now += k;
		}
	}
	return now>0;
}
int main() {
	int n, m;
	cin >> n >> m;
	int k=1;
	ren=vector<int>(n);
	for (int i=0;i<n;i++) {
		cin >> ren[i];
	}sort(ren.begin(), ren.end());
	while (jianyan(k, m)) {
		k *= 2;
	}
	int left = (k / 2),right=k;
	int mid=left;
	while(left<right) {
		mid = (left + right) / 2;
		if (jianyan(mid, m)){
			left=mid+1;
		}
		else {
			right=mid-1;
		}
	}
	while (jianyan(mid, m)) {
		mid++;
	}
	while (!jianyan(mid,m)) {
		mid--;
	}
	if (mid <= 0)mid = 1;
	cout << mid << endl;
	return 0;
}

二分法求最大值即可;

7-4 一元三次方程

给定一个形如ax3+bx2+cx+d=0的一元三次方程。

已知该方程有三个不同的实数根(根与根之差的绝对值≥10−6),且根范围均在[p,q]之间,你需要解出这个方程的三个根。

输入格式:

第一行一个整数T(1≤T≤1000),表示有T组数据

接下来T行,每行6个实数,分别表示a,b,c,d,p,q

数据保证:−102≤p,q≤102,且对于∀x∈[p,q],−106≤f(x)≤106

输出格式:

输出三个实数,表示方程的三个解。

你的答案可以以任意顺序输出。

一个答案被认为是正确的,当且仅当其与标准答案的绝对误差不超过10−6

输入样例:

在这里给出一组输入。例如:

1
1.000000 -5.000000 -4.000000 20.000000 -10.000000 10.000000

输出样例:

在这里给出相应的输出。例如:

-2.000000 2.000000 5.000000
#include<bits/stdc++.h>
using namespace std;
double sanci(double a, double b, double c, double d, double left, double right) {
	double mid = (left + right) / 2;
	while (abs(a * mid * mid * mid + b * mid * mid + c * mid + d) > 1e-6)  {
		mid = mid - (a * mid*mid*mid + b * mid *mid+ c * mid + d) / (3.0 * a * mid * mid + 2.0 * b * mid + c);
	}
	return mid;
}
int main() {
	int n;
	cin >> n;
	for (int i=0;i<n;i++) {
		double a, b, c, d, p, q;
		cin >> a >> b >> c >> d >> p >> q;
		double left = ((1.0) * (-2 * b) + sqrt(4 * b * b - 4 * 3 * a * c)) / 6 / a;
		double right= ((1.0) * (-2 * b) - sqrt(4 * b * b - 4 * 3 * a * c)) / 6 / a;
		if (left > right)swap(left, right);
		double x1 = sanci(a, b, c, d, p, left), x2 = sanci(a, b, c, d, left, right),x3=sanci(a, b, c, d, right, q);
		cout << fixed << setprecision(6) << x1 <<' ' << x2<<' ' << x3 << endl;
	}

	return 0;
}

没考虑left与right谁大;

没传double值

7-5 线性变换

题目背景

小F有一个序列 a0​,a1​,a2​,...,an−1​,他决定进行 T 轮操作,来产生一个加密值 X。

在一开始,他有一个下标 P,一对线性变换系数 K、B,加密值 X 的初始值为 0

每一轮重复如下过程:

  1. X=X+aP​​
  2. P=(K×P+B)%n

请你帮他计算这个加密值 X 最后是多少。

输入格式

第一行输入五个整数 n,P,K,B,T(1≤n≤106,0≤P<n,0≤K,B≤106,0≤T≤1012)
第二行输入 n 个整数 a0​,a1​,a2​...an−1​(0≤ai​≤106),表示这个序列。

输出格式

输出一个整数,表示最终的加密值X

输入样例1:
7 1 1 3 4 
1 4 2 2 5 10 1
输出样例1:
12
输入样例2:
8 3 2 0 2 
1 2 3 4 8 7 6 5 
输出样例2:
10
#include<bits/stdc++.h>
using namespace std;

int main() {

	long long n, p, k, b, t;
	cin >> n >> p >> k >> b >> t;
	vector<int>a(n);
	for (int i = 0; i < n; i++) {
		cin >> a[i];
	}
	vector<long long>huan;
	huan.push_back(a[p]);
	map<int,int>xunhuan;
	xunhuan.emplace(p, 0);
	p = (k * p + b) % n;
	int i;
	for (i = 1;; i++) {
		if (xunhuan.find(p)!=xunhuan.end())break;
		xunhuan.emplace(p,i);
		huan.push_back(a[p]);
		p = (k * p + b) % n;
	}
	i = (xunhuan.find(p))->second;
	vector<int>start(huan.begin(), huan.begin() + i);
	vector<int>end(huan.begin() + i, huan.end());
	long long dec = min((long long)(start.size()), t);
	long long x = accumulate(start.begin(), start.begin() + dec, 0ll);
	t -= dec;
	if (t > 0) {
		int len = end.size();
		long long tot = accumulate(end.begin(), end.end(), 0ll);
		x += t / len * tot +
			accumulate(end.begin(), end.begin() + t % len
				, 0ll);
	}
	cout << x << endl;
	/*
	8 0 4 0 100 
	1 4 2 2 5 10 1 1
	
	*/
	return 0;
}

先找循环,然后累加

忘考虑环的第一个可能不在循环

P1028 [NOIP2001 普及组] 数的计算

#include <bits/stdc++.h>
using namespace std;
int main(){
    vector<int>ans;
    int n;
    cin>>n;
    ans.push_back(1);
    ans.push_back(1);
    for(int i=2;i<=n;i++){
        int temp=1;
        for(int i1=1;i1<=i/2;i1++){
            temp+=ans[i1];
        }
        ans.push_back(temp);
    }
    cout<<ans[n]<<endl;
    return 0;    
}

合法数据包括n 和n+f(n/2)+...+f0;

然后递推

P1192 台阶问题

#include <bits/stdc++.h>
using namespace std;
int main(){
    vector<int>ans={1,1};
    int n,k;
    cin>>n>>k;
    /*
    fn=fn-1+n-2+n-3+n-4...n-k;
    f1=1;
    */
    for(int i=2;i<=n;i++){
        int temp=0;
        for(int i1=1;i1<=k;i1++){
            if(i-i1>=0){
            temp+=ans[i-i1];
            temp%=100003;
            }
        }
        ans.push_back(temp);
    }
    cout<<ans[n]<<endl;
    return 0;    
}

 
    fn=fn-1+n-2+n-3+n-4...n-k;
    f1=1

P1044 [NOIP2003 普及组] 栈

#include <bits/stdc++.h>
using namespace std;
int main(){
    vector<long long>ans={1,1};
    int n;
    cin>>n;

    for(int i=2;i<=n;i++){
        ans.push_back(ans[i-1]*(4*i-2)/(i+1));
    }
    cout<<ans[n]<<endl;
    return 0;    
}

栈的出栈序列为卡特兰数 递推公式fn=fn-1*(4*(n-1)-2)/(n+1);

P1003 [NOIP2011 提高组] 铺地毯

#include <bits/stdc++.h>
using namespace std;
struct ditan{
    int x,y;
    int a,b;
    void shuru(){
        cin>>x>>y>>a>>b;
    }
    bool fugai(int a1,int b1){
        if(a1>x+a||a1<x)return false;
        if(b1>y+b||b1<y)return false;
        return true;
    }
};
int bian(vector<ditan>&ans,int x,int y){
    for(int i=ans.size()-1;i>0;i--){
        if(ans[i].fugai(x,y))return i;
    }
    return -1;
}
int main(){
    int n;
    cin>>n;
    vector<ditan>ans(n+1);
    for(int i=1;i<=n;i++){
        ans[i].shuru();
    }
    int x,y;
    cin>>x>>y;
    cout<<bian(ans,x,y)<<endl;
    return 0;    
}

记录数据

从后往前检验即可;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值