week 4:

1:

 

 此题需要判断是否为有环图:当父节点相同时,说明为有环图,输出“No”;

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int fa[N],f;
int p[N];
int find(int x){
	if(fa[x]!=x){
		return find(fa[x]);
	}
	return fa[x];
}
int main(){
	int n,m;
	cin>>n>>m;
	for(int i=0;i<=n;i++){
		p[i]=2;
	}
//	memset(p,2,sizeof(p));
	for(int i=0;i<n;i++){
		fa[i]=i;
	}
	for(int i=0;i<m;i++){
		int a,b;
		cin>>a>>b;
		if(find(a)==find(b)){
			cout<<"No"<<endl;
			return 0;
		}
		fa[find(a)]=fa[b];
		p[a]--;
		p[b]--;
		
	}
	for(int i=1;i<=n;i++){
		if(p[i]<0){
			cout<<"No"<<endl;
			f=1;
		}
	}
	
	if(f==0)cout<<"Yes"<<endl;
	return 0;
}

2:

 方法一:暴力一个个找(少了sort会超时,因为会影响if条件1,2,3的判断,从而影响运行速度);

#include<bits/stdc++.h>
using namespace std;
int L[2010],ans;
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int N;
	cin>>N;
	for(int i=0;i<N;i++){
		cin>>L[i];
	}
sort(L,L+N);
	for(int i=0;i<N-2;i++){
		for(int j=i+1;j<N-1;j++){
			for(int k=j+1;k<N;k++){
				if(L[i]<L[j]+L[k]&&L[j]<L[i]+L[k]&&L[k]<L[j]+L[i]){
					ans++;
				}
			}
		}
	}
	cout<<ans<<endl;
	return 0;
}

 方法二:二分查找:

对数组进行降序排序,假设a>b>c;

则只需要满足b+c>a即可,当确定a,b时,c的下标越小,c越大越容易满足不等式,随着c下标的增大,c越小,需要二分查找c的临界点。

#include<bits/stdc++.h>
using namespace std;
int p[2005];
int cmp(int a,int b){
	return a>b;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	int n,l,r,mid,cut=0;
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>p[i];
	}
	sort(p,p+n,cmp);
	for(int i=0;i<n-2;i++){
		for(int j=i+1;j<n-1;j++){
			l=j+1;
			r=n-1;
			while(l<=r){
				mid=(l+r)/2;
				if(p[i]<p[j]+p[mid]){
					cut+=mid-l+1;
					l=mid+1;
				}
				else r=mid-1;
			}
		}
	}
	cout<<cut;
	return 0;
}

3 :

代码有解析:(图)

#include<bits/stdc++.h>
using namespace std;
int main(){
	int N;
	cin>>N;
	int a[N+1]={0};
	for(int i=1;i<=N;i++){
		cin>>a[i];
	}
	vector<int>b(N+1,0),s;
	int v=1;
	while(b[v]==0){
		b[v]=1;
		s.push_back(v);
		v=a[v];//寻找父节点,v到最后会等于环的"第一个数字";
	}//已经找到一个环;
	vector<int>ans;
	for(auto &pp:s){//遍历s,找到s里成环的数
		if(v==pp){//如果等于环的“第一个数”直接将后面的数存入
			v=-1;
		}
		if(v==-1){
			ans.push_back(pp);//直接存入数组
		}
	}
	cout<<ans.size()<<endl;;//输出
	for(auto &io:ans){
		cout<<io<<" ";
	}
	return 0;
}

4 :

 “一个数也是非降序”要保证任意两个数都是非降序;实现非降序数组,也就是每个数字都比之前的数字大或者相等。

当要进行k次操作时:第一个数变为a1+k,第二个变为a2+2*k,第n个数变为an+n*k;

(1<=ai<=1e12);(n<=1e5)

如果数组长度是偶数(k为偶数),总会加为非降序;

但是当数组长度为奇数时,最后一个数是没办法进行加法,所以需要将第n个数,和第n-1个数进行差值比较,从后往前看看最多能做几次加法

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+15;
int cha[N];
int a[N];
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	int T;
	cin >> T;
	while(T--){
		int n;
		cin >> n;
		for(int i=1;i<=n;i++){
			cin >> a[i];
		}
		if(n%2==0)cout<<"YES\n";//如果数组长度是偶数,一定可以成为非降序(可以操作无数次)
		else{
			int t = 0;
			for(int i=n;i>=2;i--){
				if(a[i]+t<a[i-1]){
					t=-1;
					break;
				}
				//如果i是奇数
				if(i&1){
					t += (a[i]-a[i-1]+t)/(i-1);//最多可以加几次
					cout<<t<<endl;
	
				}
				cout<<i<<endl;
			}
			if(t!=-1)cout << "YES\n";
			else cout << "NO\n";
		}
	}
	return 0;
	
}

5:

 斜着删也可以,注意n=1和n=2两种特殊情况(类似关鸡)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+15;
int a[N],b[N];
int zhi,he;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	int T;
	cin >> T;
	while(T--){
		int n;
		cin >> n;
		int ans = -1;
		if(n>2){
			ans = 2;
		}
		for(int i = 1;i<=n;i++)cin>>a[i];
		for(int i=1;i<=n;i++){
			cin>>b[i];
			if((i<n&&i>1&&b[i]==a[i])||a[i-1]==b[i]||a[i+1]==b[i])
				ans = 1;
			
		}
		cout << ans << endl;
	}
	return 0;
}

6:

 

 对于一个数x,他的左右两边加起来不能超过x-1个0,能放左边的先放左边,放不下的尽量放右边

关于贪心证明有归纳法和反证法,用归纳法证明此题

边界:只有一个的时候最优解确实是ans[0]=a[1]-1;

归纳假设:

设有n个时候的最优解是:

ans[0]=a[1]-1

ans[i]=min(a[i]-ans[i-1]-1,a[i+1]-1)

ans[n]=a[n]-ans[n-1]-1,最后一个数等于他本身减去左边的0的个数

sum是ans的前缀和

那么n个数的答案是sum[n-1]+a[n]-ans[n-1]-1

=sum[n-2]+a[n]-1

递推:N+1个时还按这个方法求出来的最优解是:

ans'[n]=min(a[n]-ans[n-1]-1,a[n+1]-1)

ans[n+1]=a[n+1]-ans'[n]-1

新的和为:

sum[n-1]+ans'[n]+ans[n+1]

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+15;
int a[N];
int zhi,he;
signed main(){
	int n;
	cin >> n;
	for(int i=0;i<n;i++){
		cin >> a[i];
	}
	int sum = 0;
	int cnt = 0;
	int mi = 1e10+15;
	for(int i=0;i<n;i++){
		if(a[i]==1){
			cnt = 0;
			mi = 1e10+15;
		}
		else{
			if(i==0 || i==n-1)continue;
			cnt++;
			if(cnt<=2)
				mi = min (mi,a[i]);
			if(cnt>=2){
				int k = min((mi -1),a[i]-1);
				sum += k;
				mi = a[i]-k;
			}
		}
	}
	if(a[0]!=1){
		sum += a[0]-1;
	}
	if(a[n-1]!=1){
		sum += a[n-1]-1;
	}
	if(n==1){
		sum = a[0]-1;
	}
	cout << sum << endl;
	return 0;
	
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值