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;
}