三月第一个周报

打了天梯赛,学到了一些东西。(补题)

描述

众所周知,ACM实验室的传奇学长Z学长非常爱喝奶茶,他非常喜欢收集各式各样的奶茶联名袋子,他目前已经拥有了 n 个不同的奶茶袋子。

在某一天,他将自己的 n 个袋子按照高度顺序从低到高放在了ACM集训队的窗台上,他希望将这些袋子分成 m 个连续段,使得所有分段的极差之和尽可能的小。

简单的来讲,你需要将一个长度为 n 的序列分为 m 段,我们定义 si​ 为第 i 个分段的极差,你需要找出最小的 ∑i=1m​si​。

极差:是指每个分段中最高和最矮的袋子高度之差,例如有一个分段为{1,2,7,10},那么极差为10−1=9。

分段:每一段在原始序列中是一段连续区间,例如将{1,2,3,4,5,6}分成两段,{1,2,3}{4,5,6} 是合法的,而类似于{1,2,4}{3,5,6}或{1,3}{4,5,6}是不合法的。

145658087d824d2c9347fd9d49e7dd80.jpg

输入描述

第一行输入两个整数 n,m(1≤m≤n≤105),代表袋子的数量和分段的数量。
第二行输入 n 个整数 a1​,a2​,...,an​,代表每个袋子的高度,其中1≤a1​≤a2​≤a3​≤...≤an​≤109。

输出描述

输出一个整数,表示最小的极差之和

用例输入 1 

5 2
2 5 7 10 13

用例输出 1 

8
#include<bits/stdc++.h>
using namespace std;
long long int a[100005];
long long int b[100005];
int main()
{
	int n,m;
	long long int sum=0;
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
	}
	for(int i=2;i<=n;i++){
		b[i]=a[i]-a[i-1];
	}
	sort(b+2,b+n+1);
	for(int i=2;i<=n-m+1;i++){
		sum+=b[i];
	}
	printf("%lld",sum);
	return 0;
}

这道题当时并没想到好的思路,但是后面了解到一个思路,插板消掉较大的临差。

描述

NoonMaple现在手里有 n 个卡片,每个卡片上都标有一个非负整数,这一天从未来穿越回来的kk为了给NoonMaple加训,他从NoonMaple手中选取两个卡片分别标有 a 和 b ,并定义

f(a,b)​=(a&b)⊕(a∣b),

kk想知道他每次抽取的两个卡片上的数字带入这个函数的出来的结果是多少。

显然这个问题对于NoonMaple来说太简单了,于是kk决定加大难度,他将NoonMaple手中的所有卡片打乱并将卡片从 1 ~ n 标号,他又定义

T(l,r)​=f(f(...f(f(al​,al+1​),al+2​)...,ar−1​),ar​),

同时连续抛出了 m 个问题,每个问题给出两个正整数 l 和 r ,要求NoonMaple在极短的时间内求出 T(l,r)​,这下可难到NoonMaple了,于是NoonMaple向你求助,你能解出这道题吗?

其中,⊕ 表示按位异或,& 表示按位与,∣ 表示按位或。

只有解出这道题,NoonMaple才能去玩他的幸运号码。

输入描述

第一行包含一个正整数 n(1≤n≤2∗105) 表示卡片的数量;

第二行包含 n 个非负整数,第 i 个非负整数 xi​(0≤xi​<232) 表示第 i 张卡片上的数字;

第三行包含一个正整数 m(1≤m≤105) 表示有 m 个问题;

接下来 m 行,每行包含两个正整数 l 和 r (1≤l<r≤n) 表示此次问题的左区间和右区间。

输出描述

包含 m 行输出,即对于每一个问题输出一个整数表示其答案。

用例输入 1 

6
1 1 2 2 3 3
3
1 2
2 3
4 6

用例输出 1 

0
3
2
#include<bits/stdc++.h>
using namespace std;
int a[200005];
int s[200005];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s[i]=(s[i-1]&a[i])^(s[i-1]|a[i]);
	}
	int m;
	cin>>m;
	for(int i=0;i<m;i++){
		int l,r;
		cin>>l>>r;
        printf("%d\n",(s[r]&s[l-1])^(s[r]|s[l-1]));
    }
	return 0;
}

这道题没找到后面的公式,后面看到题解,去推导,找到了公式。

 

描述

众所周知,赛尔号中的部分精灵可以进行融合,部分精灵也可以经过单个或多个精灵融合得到。然而在进行融合的过程中,作为融合材料的精灵需要达成一定的等级条件。

现在swj学长给了你三种精灵,分别是低级精灵,中级精灵和高级精灵。

已知三种精灵的升级条件如下:

  • 所有精灵起始等级为 1 。

  • 低级精灵:单个精灵从 1 级升到 2 级需要 1 经验,从 1 级升到 3 级需要 2 经验,从 1 级升到 4 级需要 4 经验,从 1 级升到 5 级需要 7 经验,从 1 级升到 6 级需要 11 经验,以此类推。

  • 中级精灵:单个精灵从 1 级升到 2 级需要 1 经验,从 1 级升到 3 级需要 3 经验,从 1 级升到 4 级需要 7 经验,从 1 级升到 5 级需要 13 经验,从 1 级升到 6 级需要 21 经验,以此类推。

  • 高级精灵:单个精灵从 1 级升到 2 级需要 1 经验,从 1 级升到 3 级需要 6 经验,从 1 级升到 4 级需要 16 经验,从 1 级升到 5 级需要 31 经验,从 1 级升到 6 级需要 51 经验,以此类推。

现在swj学长想要融合出一个特定的精灵 x,现在告诉了你融合出对应精灵所需的材料精灵和材料精灵所需到达的等级。swj经过努力已经集齐了所有不需要通过融合就能获得的所有精灵且他们的当前等级均为 1 级。现在他想让你帮忙算算看,融合出精灵 x 一共需要多少经验值?

输入描述

第一行输入两个整数 x 和 m(1≤x,m≤105)。 x代表需要融合出的最终精灵编号,m代表融合关系总数;

接下来m行,每行输入四个整数 a,b,c,d(1≤a,b≤105),(1≤c≤3),(1≤d≤100)

a 代表可被融合出的精灵编号。

b 代表融 a 精灵所需的材料精灵编号。

c 代表精灵 b 的种类,1 为低级精灵,2 为中级精灵,3 为高级精灵。

d 代表精灵 b 作为融合 a 的材料精灵所需到达的等级;

数据保证每个精灵最多有一种合成公式,每个精灵最多作为一种精灵的材料精灵。

输出描述

输出一个整数,说明融合出精灵 x 一共需要多少经验。

用例输入 1 

1 3
1 2 1 5
2 3 2 5
2 4 3 5

用例输出 1 

51

用例输入 2 

1 4
1 2 1 20
2 3 2 30
1 4 3 40
1 6 1 50

用例输出 2 

5868
#include<bits/stdc++.h>
using namespace std;
vector<int>d[100010];
map<pair<int,int>,long long>mp;
long long int sum=0;
long long huafei(int x,int y){
	if(y==1){
		return 0;
	}
	y--;
	if(x==1)
		return (1+y-1)*(y-1)/2+1;
	else if(x==2)
		return (2+(y-1)*2)*(y-1)/2+1;
	else
		return (5+(y-1)*5)*(y-1)/2+1;
}
void dfs(int x){
	for(auto e:d[x]){
		sum+=mp[{x,e}];
		dfs(e);
	}
}
int32_t main(){
	int X,m;
	cin>>X>>m;
	for(int i=1;i<=m;i++){
		int a,b,c,e;
		cin>>a>>b>>c>>e;
		mp[{a,b}]=huafei(c,e);
		d[a].push_back(b);
	}
	dfs(X);
	cout<<sum<<endl;
	return 0;
}

根本没想法,后面简单的dfs,map,vector学的这些,把题补上了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值