23.11.12周报

星期一每日三题:

A 题:

题意:n个积木柱,每个柱子有hi块积木,每次能移除高度h以上的积木,单次限制条件为移除总积木数不超过k(k给出,h任意),要使所有积木等高,问最少移除多少次。

思路:贪心,前缀和。先排序,然后经过一番处理(较为繁琐),得出下标为高度的需移除积木数的后缀和数组。开始我想着用二分找移除高度,后来t了,想了下其实没必要,就从高到0遍历了一遍高度,得出了移除次数。虽然感觉并不难,但写了半天代码。。

代码如下:

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using PII=pair<int,int>;

const int N=2e5+10;
int n,k;
int h[N];
int cnt1[N];
ll cnt[N],ans;
void solve(){
	cin >> n >> k;
	for(int i=1;i<=n;i++){
		cin >> h[i];
	}
	if(n==1){cout << 0; return ;}
	sort(h+1,h+n+1,greater<int>());
	if(h[1]==h[n]){cout << 0; return ;}
	for(int i=1;i<=n;i++){
		h[i]=h[i]-h[n];
	}
	for(int i=1;i<=n;i++){
		cnt1[h[i]]=i;
	}
	cnt[h[1]]=cnt1[h[1]];int kk=cnt[h[1]];
	for(int i=h[1]-1;i;i--){
		if(cnt1[i]==0) cnt[i]=cnt[i+1]+kk;
		else kk=cnt1[i],cnt[i]=cnt[i+1]+kk;
	}
	ll tmp=0;
	for(int i=h[1];i;i--){
		if(tmp+k<cnt[i-1]) tmp=cnt[i],ans++;
	}
	cout << ans+1;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	//cin >> t;
	while(t--) solve();
	return 0;
}
//make it count
//开ll plz

周二比赛:

A题:之前做过,不讲了.

B题:

题意:给出长度为n序列,要求输出n/2个不同数对,满足三个条件,一x!=y,二x,y是a中的数,三x模y不能在a中.

思路:根据条件一三,得x必须严格大于y.刚开始想的是开个筛子数组,出现过的数都标记一下,然后以on²的复杂度挨个找,找到n/2个数对就break,但tle.后来发现x%y的结果一定是严格小于y的,并且数对 数量也不多,只需n/2个,那么可以用on的复杂度,用每个数和a中最小数进行判断.

代码如下:

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using PII=pair<int,int>;

const int N=2e5+10;
int n;
int a[N];
int cnt;
void solve(){
	cnt=0;
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> a[i];
	}
	sort(a+1,a+n+1);
	for(int i=2;i<=n;i++){
		if(a[i]!=a[i-1]) cout << a[i] << " " << a[1] << endl;
		cnt++;
		if(cnt==n/2) break;
	}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	cin >> t;
	while(t--) solve();
	return 0;
}
//make it count
//开ll plz

星期三每日三题:

A题:

题意:自行理解

思路:无需多言

代码如下:

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using PII=pair<int,int>;

const int N=3e5+10;
int n,m,minn;
int a[N],b[N];
ll suma,sumb;
ll tmpa,tmpb;
int ans;
void solve(){
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> a[i];
		suma+=a[i];
	}
	cin >> m;
	for(int i=1;i<=m;i++){
		cin >> b[i];
		sumb+=b[i];
	}
	if(suma!=sumb){cout << -1; return ;}
	minn=min(n,m);
	for(int idxa=1,idxb=1;idxa<=n;){
		tmpa+=a[idxa++],tmpb+=b[idxb++];
		while(tmpa!=tmpb){
			if(tmpa>tmpb) tmpb+=b[idxb++];
			else tmpa+=a[idxa++];
		}
		ans++,tmpa=0,tmpb=0;
	}
	cout << ans;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	//cin >> t;
	while(t--) solve();
	return 0;
}
//make it count
//开ll plz

B题:

题意:抓鼠鼠,有n个房间,每个房间放陷阱的代价是ci,有一a数组,老鼠每秒从i房间跑到a[i]房间(i.e.从a[i]房间跑到a[a[i]]房间),不知道老鼠初始在哪个房间,问最小布置陷阱代价,确保一定能捉住老鼠。

思路: 感觉很有意思的一道题,最开始想到的是并查集,但因为太久没写并查集所以去网上看,还有用图写的,打算图和并查集的写法都做一遍.

老鼠的路线有四种可能性,单点,链,环,链和环相连.链就在最后一点放陷阱,后两种在环中代价最小处放陷阱.

代码1如下:

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using PII=pair<int,int>;

const int N=2e5+10;
int n;
int c[N],a[N],vi[N];
ll ans;
void solve(){
	cin >> n;
	for(int i=1;i<=n;i++){
		cin >> c[i];
	}
	for(int i=1;i<=n;i++){
		cin >> a[i];
	}
	for(int i=1;i<=n;i++){
		int x=i;
		while(!vi[x]){
			vi[x]=i;
			x=a[x];
		}
		if(vi[x]!=i) continue;
		int cc=c[x],tmp=a[x];
		while(tmp!=x){
			cc=min(c[tmp],cc);
			tmp=a[tmp];
		}
		ans+=cc;
	}
	cout << ans;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	//cin >> t;
	while(t--) solve();
	return 0;
}
//make it count
//开ll plz

星期五打了个比赛,打麻了,脑子不知道在想什么,手不知道在敲什么。

星期六打了个比赛,a了俩道,其中一道纯纯签到题。

另一道:

题意:题面有点恶心,大意为给一算式,输出其结果奇偶性,然后m次输入x,y,把第x个数改为y,输出修改后结果奇偶性(修改保留)。

思路:有点繁琐,自己看代码。

代码如下:

#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using PII=pair<int,int>;

const int N=1e5+10;
int n,m;
char op[N];
int a[N];
bool vi[N];
vector<int>ve;
int res;
bool ans;
void solve(){
	cin >> n >> m;
	for(int i=1;i<=n;i++){
		int tmp;char c;
		cin >> tmp;
		if(tmp&1) a[i]=1,vi[i]=1;
		else a[i]=0,vi[i]=0;
		if(i==n) break;
		cin >> c;
		op[i]=c;
	}
	int cnt=0;
	for(int i=1;i<n;i++){
		if(op[i]!='*'){
			if(!(a[i]&1)) cnt++;
			ve.push_back(cnt);
			a[i]=ve.size()-1;
			cnt=0;
		}else{
			while(op[i]=='*'){
				if(!(a[i]&1)) cnt++;
				a[i]=ve.size();
				i++;
			}
			if(!(a[i]&1)) cnt++;
			ve.push_back(cnt);
			a[i]=ve.size()-1;
			cnt=0;
		}
	}
	if(op[n-1]=='*'){
		a[n]=ve.size()-1;
	}else{
		if(a[n]&1) ve.push_back(0);
		else ve.push_back(1);
		a[n]=ve.size()-1;
	}
//	for(int i=1;i<=n;i++) cout << a[i] << " ";cout << endl;
	for(auto i:ve){
//		cout << i;
		if(i==0) res++;
	}	
	if(res&1) ans=1;
	else ans=0;
	if(ans) cout << "odd" << endl;
	else cout << "even" << endl;
	while(m--){
		int x,y;
		cin >> x >> y;
		if(y&1 && vi[x]==0){
			vi[x]=1;
			ve[a[x]]--;
			if(ve[a[x]]==0) res++;
			if(res&1) ans=1;
			else ans=0;
		}else if(!(y&1) && vi[x]==1){
			vi[x]=0;
			if(ve[a[x]]==0) res--;
			ve[a[x]]++;
			if(res&1) ans=1;
			else ans=0;
		}
		if(ans) cout << "odd" << endl;
		else cout << "even" << endl;
	}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t=1;
	//cin >> t;
	while(t--) solve();
	return 0;
}
//make it count
//开ll plz

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值