钟老头的一键三连
题:https://www.luogu.com.cn/problem/P3144
题意:给出n个点m条边的图,逐一删除每个指定点,问每次删除前图是否连通。
分析:把指定的序列反过来做就行,对于每个加进来的点,看原本集合中有无进来点的连边,有就用并查集联系起来,表示俩者所处连通块连通,(正着切断,反着就判断连通与否就行),每次检查当前集合是否连通即可,复杂度:O(nlogn)
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const ll INF=1e18; const int M=3e5+6; #define pb push_back #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r int f[M],sz[M],a[M],ans[M]; set<int>s; vector<int>g[M]; int Find(int x){ return x==f[x]?x:f[x]=Find(f[x]); } void unite(int u,int v){ int x=Find(u),y=Find(v); if(x!=y){ f[y]=x,sz[x]+=sz[y]; } } int main(){ ios::sync_with_stdio(false); cin.tie(0); int n,m; cin>>n>>m; for(int i=1;i<=n;i++) f[i]=i,sz[i]=1; for(int u,v,i=1;i<=m;i++){ cin>>u>>v; g[u].pb(v); g[v].pb(u); } for(int i=1;i<=n;i++) cin>>a[i]; int sign=a[n]; for(int i=n;i>=1;i--){ int u=a[i]; s.insert(u); for(auto v : g[u]){ if(s.count(v)) unite(u,v); } if(sz[Find(sign)]==s.size()) ans[i]=1; } for(int i=1;i<=n;i++) if(ans[i]) cout<<"YES"<<'\n'; else cout<<"NO"<<'\n'; return 0; }
题:https://www.luogu.com.cn/problem/P3146
题意:给定序列,你能执行这样的操作:当相邻的值是相同的时候就可讲俩者合并成当前值加1,问最大合并出的值是多少
分析:区间dp,dp[i][j]表示区间[i,j]能合并成的最大值;
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const ll INF=1e18; const int M=300; #define pb push_back #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r int dp[M][M]; int main(){ ios::sync_with_stdio(false); cin.tie(0); memset(dp,-1,sizeof(dp)); int n,ans=0; cin>>n; for(int i=1;i<=n;i++) cin>>dp[i][i],ans=max(ans,dp[i][i]); for(int i=1;i<=n;i++){ for(int j=i-1;j>=1;j--) for(int k=j;k<i;k++){ if(dp[j][k]==dp[k+1][i]&&dp[j][k]!=-1) dp[j][i]=max(dp[j][i],dp[j][k]+1); ans=max(ans,dp[j][i]); } } cout<<ans<<endl; return 0; }
题:http://acm.hdu.edu.cn/showproblem.php?pid=4623
题意:找出n的排列中满足相邻相邻互质的个数
分析:咕咕咕