2021牛客暑期多校训练营6

2021牛客暑期多校训练营6

C:Delete_Edges

解释

结论题。题目转换为从n个点中任意选择三个点,使得三个点不会重复出现的方案数。

输出 ( x + y + z ) % n = = 0 , 1 < = x < y < z < = n (x + y + z) \% n == 0,1 <= x < y < z <= n (x+y+z)%n==0,1<=x<y<z<=n

代码

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
//#define int long long

struct Node{
	int a,b,c;
};
vector<Node> ans;

signed main(){
	IOS
	#ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
	int n; cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=i+1;j<=n;j++){
			int z = n - i - j;
			if(z <= 0) z += n;
			if(z <= j) continue;
			ans.push_back({i,j,z});
		}
	cout<<(int)ans.size()<<endl;
	for(auto i : ans) cout<<i.a<<" "<<i.b<<" "<<i.c<<"\n";
	return 0;
}

F:Hamburger_Steak

解释

二分,假设答案时间为m,按顺序放,当放到一个物品超过m则分开,放到下一个锅。l一定大于等于最长时间,这样可以保证不会有一个汉堡不会在一个时间出现在两个锅里面。

最优时间可以计算。 m i d = m a x ( m a x ( a i , a i + 1 , . . . ) , ( s u m + m − 1 ) / m ) mid = max(max(a_i,a_{i+1},...),(sum+m-1)/m) mid=max(max(ai,ai+1,...),(sum+m1)/m)

这样可以去掉二分部分。直接调用slove。

代码

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;

const int INF = 0x3f3f3f3f;
const double eps = 1e-5;
const int N = 2e5+10;
const int mod = 998244353;

int a[N],n,m;

bool check(int mid){
	int cursum = 0,j = 1;
	for(int i=1;i<=n;i++){
		if(cursum + a[i] > mid){
			j ++;
			cursum = cursum + a[i] - mid;
		}else{
			cursum += a[i];
			if(cursum == mid){
				if(i != n) j ++;
				cursum = 0;
			}
		}
	}
	return j <= m;
}

void slove(int mid){
	int cursum = 0,j = 1;
	for(int i=1;i<=n;i++){
		if(cursum + a[i] > mid){
			j ++; int k = cursum;
			cursum = cursum + a[i] - mid;
			cout<<2<<" "<<j<<" "<<0<<" "<<cursum<<" "<<j-1<<" "<<k<<" "<<mid<<endl;
		}else{
			cursum += a[i];
			cout<<1<<" "<<j<<" "<<cursum-a[i]<<" "<<cursum<<endl;
			if(cursum == mid){
				if(i != n) j ++;
				cursum = 0;
			}
		}
	}
}

signed main(){
	IOS
    int ma = 0; cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i],ma = max(ma,a[i]);
    int l = ma,r = 1e14;
    while(l < r){
    	int mid = (l + r) >> 1;
    	if(check(mid)) r = mid;
    	else l = mid + 1;
	}
	slove(r);
	return 0;
}

H:Hopping_Rabbit

解释

跳的路线可以画成一个环,然后还可以把每(0 ~ d) x (0 ~ d) 的一个区域重叠到一起,然后将所有区域分割合到一个区域,之后就是扫描线格式,枚举 (0 ~ d) 当某一列或者某一行不存在被覆盖的位置,则输出那个位置.

分割需要注意。下面让 ( x 1 , y 1 ) , ( x 2 − 1 , y 2 − 1 ) (x1,y1),(x2-1,y2-1) (x1,y1),(x21,y21) 代表可跳矩阵,然后对d取mod后移到相应位置。因为扫描线是要用矩阵,所以可跳矩阵变成 ( x 1 , y 1 ) , ( x 2 + 1 , y 2 + 1 ) (x1,y1),(x2+1,y2+1) (x1,y1),(x2+1,y2+1) ,之后维护扫描线。

代码

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;

int cnt = 0,n,d;
struct Point{
	int x,y1,y2;
	int k;
	bool operator <(const Point&T)const{
		return x < T.x;
	}
}point[N];

#define l(x) t[x].l
#define r(x) t[x].r
#define cnt(x) t[x].cnt
#define len(x) t[x].len

struct SegmentTree{
	int l,r,cnt;
	double len;
}t[N << 2];

void push_up(int p,int l,int r){
	if(cnt(p)) len(p) = r - l + 1;
	else if(l == r) len(p) = 0;
	else len(p) = len(p<<1) + len(p<<1|1);
}

void build(int p,int l,int r){
	l(p) = l,r(p) = r;cnt(p) = len(p) = 0;
	if(l == r) return ;
	int mid = (l + r) >> 1;
	build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}

void update(int p,int l,int r,int k){
	if(l <= l(p) && r(p) <= r){
		cnt(p) += k;
		push_up(p,l(p),r(p));
		return ;
	}
	int mid = (l(p) + r(p)) >> 1;
	if(l <= mid) update(p<<1,l,r,k);
	if(r > mid) update(p<<1|1,l,r,k);
	push_up(p,l(p),r(p));
}

int query(int p){
	if(len(p) == 0) return l(p);
	int mid = (l(p) + r(p)) >> 1;
	if(len(p<<1) < (mid - l(p) + 1)) return query(p<<1);
	else return query(p<<1|1);
}

void md(int &x){
	x = (x % d + d) % d;
}

void split(int x1,int x2,int y1,int y2){
	md(x1),md(x2),md(y1),md(y2);
	x2 ++;y2 ++;
	if(x1 < x2 && y1 < y2){
		point[++ cnt] = {x1,y1,y2,1};point[++ cnt] = {x2,y1,y2,-1};
	}else if(x1 > x2 && y1 < y2){
		point[++ cnt] = {0,y1,y2,1};point[++ cnt] = {x2,y1,y2,-1};
		point[++ cnt] = {x1,y1,y2,1};point[++ cnt] = {d,y1,y2,-1};
	}else if(x1 < x2 && y1 > y2){
		point[++ cnt] = {x1,0,y2,1};point[++ cnt] = {x2,0,y2,-1};
		point[++ cnt] = {x1,y1,d,1};point[++ cnt] = {x2,y1,d,-1};
	}else{
		point[++ cnt] = {0,0,y2,1};point[++ cnt] = {x2,0,y2,-1};
		point[++ cnt] = {0,y1,d,1};point[++ cnt] = {x2,y1,d,-1};
		point[++ cnt] = {x1,0,y2,1};point[++ cnt] = {d,0,y2,-1};
		point[++ cnt] = {x1,y1,d,1};point[++ cnt] = {d,y1,d,-1};
	}
}

signed main(){
	IOS
	#ifdef ddgo
		freopen("C:\\Users\\asus\\Desktop\\ddgoin.txt","r",stdin);
    #endif
	cin>>n>>d;
	for(int i=0;i<n;i++){
		int x1,x2,y1,y2; cin>>x1>>y1>>x2>>y2;
		x2 --, y2 --;
		if(x2 - x1 + 1 >= d) x1 = 0,x2 = d-1;
		if(y2 - y1 + 1 >= d) y1 = 0,y2 = d-1;
		split(x1,x2,y1,y2);
	}
	sort(point+1,point+cnt+1);
	build(1,0,d-1);
	int ansx = -1;
	for(int i=0,j=1;i<d;i++){
		while(j <= cnt && point[j].x <= i){
			int l = point[j].y1,r = point[j].y2-1,k = point[j].k;
			update(1,l,r,k);
			j ++;
		}
		if(len(1) == d) continue;
		ansx = i;
		break;
	}
	if(ansx == -1) cout<<"NO"<<endl;
	else cout<<"YES\n"<<ansx<<" "<<query(1)<<endl;
	return 0;
}

I:Intervals_on_the_Ring

解释

将l > r 的区间开,1 ~ l , r ~ n, 将区间排序。

假设得到区间 ( l 1 , r 1 ) , ( l 2 , r 2 ) , ( l 3 , r 3 ) (l1,r1),(l2,r2),(l3,r3) (l1,r1),(l2,r2),(l3,r3)

输出 ( l 3 , r 2 ) , ( l 2 , r 1 ) , ( l 1 , r 3 ) (l3,r2),(l2,r1),(l1,r3) (l3,r2),(l2,r1),(l1,r3) 枚举每一个间隙,输出除这个间隙以外的区间。

代码

#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e3 + 10;
const int mod = 1e9 + 7;
const double eps = 1e-8;
const int INF = 0x3f3f3f3f;
typedef pair<int,int> pii;
typedef long long ll;

signed main(){
	IOS
    int tt; cin>>tt;
    while(tt --){
    	int n,m; cin>>n>>m;
    	vector<pii> ve;
    	int minr = INF,maxl = -1;
    	for(int i=1;i<=m;i++){
    		int l,r; cin>>l>>r;
    		if(l > r){
    			maxl = max(maxl,r);
    			minr = min(minr,l);
			}else{
				ve.push_back({l,r});
			}
		}
		if(minr <= n) ve.push_back({minr,n});
		if(maxl >= 1) ve.push_back({1,maxl});
		sort(ve.begin(),ve.end()); 
		int len = (int)ve.size();
		cout<<len<<endl;
		for(int i=len-1;i>=1;i--) cout<<ve[i].first<<" "<<ve[i-1].second<<endl;
		cout<<ve[0].first<<" "<<ve[len-1].second<<endl;
	}
	return 0;
}

J:Defend_Your_Country

解释

连通块偶数节点贡献乘上1,奇数乘上-1,求删边,使得所有贡献值之和最大。

  1. 若n为偶数,则不删。
  2. 若n为奇数,则删一个最小值的点。若为割点且删掉之后子连通块有奇数,则往后面找。

用tarjan找割点顺便求出删除这个割点是否满足子连通块全为偶数

注意各种初始化

代码

#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
typedef long long ll;

int ne[N],e[N],h[N],w[N],idx=1;
int dfn[N],low[N],cut[N],tim;
int si[N],ok[N];

void add(int a,int b){
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void tarjan(int u,int fa){
    dfn[u] = low[u] = ++tim;
    int child = 0;
    si[u] = 1;
    for(int i=h[u];i;i=ne[i]){
        int j = e[i];
        if (!dfn[j]){
            tarjan(j,fa);
            low[u] = min(low[u],low[j]);
            if(low[j] >= dfn[u] && u != fa) cut[u] = 1;
            if(u == fa) child++;
            si[u] += si[j];
            if(low[j] >= dfn[u] && si[j] % 2) ok[u] = 0;
            // 写成if(cut[u] && si[j] % 2) 则最后还要额外判断fa的子连通块是否有奇数
        }
        low[u] = min(low[u],dfn[j]);
    }
    if(child >= 2 && u == fa) cut[u] = 1;
}

signed main(){
    int tt; scanf("%d",&tt);
    while(tt --){
    	int n,m; scanf("%d %d",&n,&m);
    	ll sum = 0;
	    for(int i=1;i<=n;i++) scanf("%d",&w[i]),sum += w[i];
	    for(int i=1;i<=n;i++) cut[i] = dfn[i] = low[i] = 0,ok[i] = 1;
	    for(int i=1;i<=idx;i++) h[i] = 0;
	    tim = 0; idx = 1;
	    for(int i=1;i<=m;i++){
	    	int a,b; scanf("%d %d",&a,&b);
	    	add(a,b);add(b,a);
		}
		if(n % 2 == 0) printf("%lld\n",sum);
		else{
			tarjan(1,1);
			ll res = 1e18;
			for(int i=1;i<=n;i++) if(ok[i]) res = min(res,(ll)w[i]);
			sum -= 2*res;
			printf("%lld\n",sum);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值