- CF25D Roads not only in Berland
- CF1205B Shortest Cycle
- CF1242B 0-1 MST
- CF1307D Cow and Fields
- CF1228D Complete Tripartite
- CF1245D Shichikuji and Power Grid
- CF1272E Nearest Opposite Parity
- CF558C Amr and Chemistry
- CF25C Roads in Berland
- CF711D Directed Roads
1.CF25D Roads not only in Berland
Main idea:find all the loops and break it,connet all the components.
Thinking of problem solving:DSU on tree
For each edges,if the vertex u and v are already in the same connected components,record it and with set.After that,ergodic the set,find the components which it different from it and connect it.
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=1005,inf=0x3f3f3f3f;
int f[maxn],n,m,vis[maxn],ans;
vector<int>e[maxn];
set<pair<int,int>>st;
struct w{
int a,b,c,d;
}q[maxn];
int find(int x){
if(f[x]==x)return x;
else return f[x]=find(f[x]);
}
inline void hb(int x,int y){
int fx=find(x);
int fy=find(y);
f[fx]=fy;
}
int main(){
cin>>n;
for(int i=1;i<=n;i++){
f[i]=i;
}
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
if(find(u)!=find(v))hb(u,v);
else st.insert({u,v});
}
for(auto x:st){
int fa=find(x.first);
for(int i=1;i<=n;i++){
if(find(i)==fa)continue;
q[++ans]=((w){x.first,x.second,x.first,i});
hb(x.first,i);
break;
}
}
cout<<ans<<endl;
for(int i=1;i<=ans;i++){
printf("%d %d %d %d\n",q[i].a,q[i].b,q[i].c,q[i].d);
}
return 0;
}
2.CF1205B Shortest Cycle
Main idea:You are given n n n integer numbers a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an . Consider graph on n n n nodes, in which nodes i i i , j j j ( i ≠ j i\neq j i=j ) are connected if and only if, a i a_i ai & a j ≠ 0 a_j\neq 0 aj=0
Thinking of problem solving:Floyd,Special judge.
According to the drawer principle,if the number of numbers greater than 128,there must be 3 numbers with 1 in its bitmask.So the answer will be 3.
If the number of numbers less than 128,we can ergodic all the numbers and connect them,and then run the floyd algorithm to find the smallest loop.
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=130,inf=1e12;
int n,m;
int a[maxn];
int dis[maxn][maxn],mp[maxn][maxn];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
if(i>=128){
cout<<3;
return 0;
}
cin>>a[i];
if(!a[i]){
n--;
i--;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
if((a[i]&a[j])){
dis[i][j]=1;
dis[j][i]=1;
mp[i][j]=1;
mp[j][i]=1;
}
else{
dis[i][j]=inf;
dis[j][i]=inf;
mp[i][j]=inf;
mp[j][i]=inf;
}
}
}
int ans=inf;
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j||i==k||j==k)continue;
ans=min(ans,dis[i][j]+mp[i][k]+mp[j][k]);
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
if(abs(ans)<=inf/2)cout<<ans;
else cout<<"-1";
return 0;
}
3.CF1242B 0-1 MST
Main idea:find the number of connected components in the complement graph.
Thinking of problem solving:
First,chose the first vertex and mark all vertex connected to it,then combine all the vertex which has been not marked.
Second,traverse all the vertexes,for each vertex,mark all vertexes connected to it,and combine all the vertex which has been not marked like the first vertex.
In the end,traverse all vertexes and to count the answes.
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=2e5+5,inf=0x3f3f3f3f;
int n,m,k,t,cnt,tt;
int f[maxn],vis[maxn],v[maxn],size[maxn],du[maxn];
vector<int>e[maxn];
inline void add(int u,int v){
e[u].push_back(v);
}
int find(int x){
if(f[x]==x)return x;
else return f[x]=find(f[x]);
}
inline void hb(int x,int y){
f[find(x)]=find(y);
}
set<pair<int,int>>st;
signed main(){
cin>>n>>m;
int mm=inf;
int id;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
du[u]++,du[v]++;
}
for(int i=1;i<=n;i++){
if(du[i]<mm){
mm=du[i];
id=i;
}
f[i]=i;
}
for(auto x:e[id]){
vis[x]=1;
}
for(int i=1;i<=n;i++){
if(!vis[i]){
hb(i,id);
}
}
int tim=1;
for(int i=1;i<=n;i++){
if(!vis[i]||i==id)continue;
tim++;
memset(v,0,sizeof v);
for(auto x:e[i]){
v[x]=1;
}
for(int j=1;j<=n;j++){
if(!v[j]){
hb(i,j);
}
}
}
for(int i=1;i<=n;i++){
if(f[i]==i){
cnt++;
}
size[find(i)]++;
}
for(int i=1;i<=n;i++){
if(f[i]==i){
st.insert({size[i],i});
}
}
cout<<cnt-1<<endl;
/*for(auto x:st){
cout<<x.first<<" ";
}*/
return 0;
}
4.CF1307D Cow and Fields
Main idea:give you a bidirectional graph and a sequence with k vertex,you will chose two vertex from it and connect them,print the max value of shortest path from 1 to n.
Thinking of problem solving:pretreat the shortest path 1 to others and n to others,traverse all vertex and update the ans.
for(int i=1;i<=k-1;i++){
ans=max(ans,dis1[a[i]]+dis2[a[i+1]]+1);
}
the new value of shortest path between 1 and n is min(ans,dis[1,n]).
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=2e5+5,inf=0x3f3f3f3f;
int n,m,k,dis1[maxn],dis2[maxn],a[maxn],vis[maxn];
vector<int>e[maxn];
inline void bfs1(){
memset(vis,0,sizeof vis);
dis1[1]=0;
queue<int>q;
q.push(1);
vis[1]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(auto v:e[u]){
if(vis[v])continue;
dis1[v]=dis1[u]+1;
vis[v]=1;
q.push(v);
}
}
}
inline void bfs2(){
memset(vis,0,sizeof vis);
dis2[n]=0;
queue<int>q;
q.push(n);
vis[n]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(auto v:e[u]){
if(vis[v])continue;
dis2[v]=dis2[u]+1;
vis[v]=1;
q.push(v);
}
}
}
int main(){
cin>>n>>m>>k;
for(int i=1;i<=k;i++){
cin>>a[i];
}
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
bfs1();
bfs2();
int res=dis1[n];
sort(a+1,a+1+k,[](int x,int y){return dis1[x]<dis1[y];});
int ans=-inf;
for(int i=1;i<=k-1;i++){
ans=max(ans,dis1[a[i]]+dis2[a[i+1]]+1);
}
cout<<min(ans,res);
}
5.CF1228D Complete Tripartite
Main idea:divide all vertex into tree sets,for each vertex in the a set,must be connected to all vertex of the other two sets,and there are no edges between two vertex in the same set.
Thinking of problem solving:coloring the graph,hash,mark each vertex’s degree.
#include<bits/stdc++.h>
using namespace std;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f;
int n,m;
int a[maxn*3],b[maxn*3];
int col[maxn],vis[maxn],cnt1,cnt2,cnt3,cnt;
int c1[maxn],c2[maxn],c3[maxn];
vector<int>e[maxn];
unordered_map<int,int>mp;
void dfs(int u,int fa){
vis[u]=1;
for(auto v:e[u]){
if(v==fa)continue;
if(!vis[v]){
dfs(v,u);
}
}
}
int main(){
cin>>n>>m;
int flag=0;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
a[i]=u;
b[i]=v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1,1);
for(int i=1;i<=n;i++){
cnt+=vis[i];
}
if(cnt!=n)flag=1;
memset(vis,0,sizeof vis);
for(auto v:e[1]){
vis[v]=1;
}
for(int i=1;i<=n;i++){
if(!vis[i])col[i]=1,c1[++cnt1]=i,mp[i]=1;
}
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++){
if(!col[i]){
for(auto v:e[i]){
if(col[v]==1)continue;
col[v]=2;
c2[++cnt2]=v;
mp[v]=2;
}
break;
}
}
memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++){
if(!col[i]){
col[i]=3;
c3[++cnt3]=i;
mp[i]=3;
}
}
if(cnt1+cnt2+cnt3!=n)flag=1;
memset(vis,0,sizeof vis);
for(int i=1;i<=m;i++){
int u=a[i];
int v=b[i];
vis[u]++,vis[v]++;
if(mp[a[i]]==mp[b[i]]){
flag=1;
break;
}
}
for(int i=1;i<=cnt1;i++){
if(vis[c1[i]]!=cnt2+cnt3){
flag=1;
break;
}
}
for(int i=1;i<=cnt2;i++){
if(vis[c2[i]]!=cnt1+cnt3){
flag=1;
break;
}
}
for(int i=1;i<=cnt3;i++){
if(vis[c3[i]]!=cnt1+cnt2){
flag=1;
break;
}
}
if(cnt1==0||cnt2==0||cnt3==0)flag=1;
if(flag)puts("-1");
else{
for(int i=1;i<=n;i++){
cout<<col[i]<<" ";
}
}
// printf("%d %d %d",cnt1,cnt2,cnt3);
return 0;
}
6.CF1245D Shichikuji and Power Grid
Main idea:you can choose some vertex to set site,and make all the vertex connect.
Thinking of problem solving:MST
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=2005,inf=0x3f3f3f3f;
struct edge{
int u,v,w;
}e[maxn*maxn];
struct node{
int x,y;
}a[maxn];
int n,m,cnt,t,c[maxn],k[maxn],f[maxn];
vector<int>z;
vector<pair<int,int>>p;
int find(int x){
if(f[x]==x)return x;
else return f[x]=find(f[x]);
}
inline void hb(int x,int y){
f[find(x)]=find(y);
}
inline int krus(){
for(int i=1;i<=n;i++){
f[i]=i;
}
sort(e+1,e+1+cnt,[](edge x,edge y){return x.w<y.w;});
int res=0;
int ans=0;
for(int i=1;i<=cnt;i++){
int u=find(e[i].u);
int v=find(e[i].v);
if(u==v)continue;
hb(u,v);
if(!e[i].u||!e[i].v){
if(e[i].u)z.emplace_back(e[i].u);
if(e[i].v)z.emplace_back(e[i].v);
}
else{
p.push_back({e[i].u,e[i].v});
}
ans+=e[i].w;
res++;
if(res==n)return ans;
}
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
}
for(int i=1;i<=n;i++)cin>>c[i];
for(int i=1;i<=n;i++)cin>>k[i];
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j)continue;
e[++cnt].u=i;
e[cnt].v=j;
e[cnt].w=(k[i]+k[j])*(abs(a[i].x-a[j].x)+abs(a[i].y-a[j].y));
}
}
for(int i=1;i<=n;i++){
e[++cnt].u=0;
e[cnt].v=i;
e[cnt].w=c[i];
}
cout<<krus()<<endl;
cout<<z.size()<<endl;
for(auto x:z){
cout<<x<<" ";
}
cout<<endl;
cout<<p.size()<<endl;
for(auto x:p){
printf("%lld %lld\n",x.first,x.second);
}
return 0;
}
7.CF1272E Nearest Opposite Parity
Main idea:You are given an array a a a consisting of n n n integers. In one move, you can jump from the position i i i to the position i − a i i - a_i i−ai (if 1 ≤ i − a i 1 \le i - a_i 1≤i−ai ) or to the position i + a i i + a_i i+ai (if i + a i ≤ n i + a_i \le n i+ai≤n ).
For each position i i i from 1 1 1 to n n n you want to know the minimum the number of moves required to reach any position j j j such that a j a_j aj has the opposite parity from a i a_i ai (i.e. if a i a_i ai is odd then a j a_j aj has to be even and vice versa).
Thinking of problem solving:for each vertex,let the vertex after moving as its father,if it can reach the end for one move,add it into the queue.
start the bfs,for each vertex,if the vertex v’s distance has not been figured,and the value a [ u ] a[u] a[u] is equal to a [ v ] a[v] a[v],then the answer of vertex v -> d i s [ v ] dis[v] dis[v] is equal to d i s [ u ] + 1 dis[u]+1 dis[u]+1
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=2e5+5,inf=0x3f3f3f3f;
int n,m,cnt,t,a[maxn],dis[maxn];
vector<int>e[maxn];
void bfs(){
queue<int>q;
for(int i=1;i<=n;i++){
if(dis[i]==1){
q.push(i);
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(auto v:e[u]){
if(dis[v]!=-1)continue;
if((a[u]&1)==(a[v]&1))dis[v]=dis[u]+1;
q.push(v);
}
}
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
dis[i]=-1;
}
for(int i=1;i<=n;i++){
if(i+a[i]>=1&&i+a[i]<=n){
e[i+a[i]].emplace_back(i);
if(((a[i]&1)^(a[i+a[i]]))&1)dis[i]=1;
}
if(i-a[i]>=1&&i-a[i]<=n){
e[i-a[i]].emplace_back(i);
if(((a[i]&1)^(a[i-a[i]]))&1)dis[i]=1;
}
}
bfs();
for(int i=1;i<=n;i++){
cout<<dis[i]<<" ";
}
return 0;
}
8.CF558C Amr and Chemistry
Main idea:there are n numbers,you have two operations:
1.multiply a number by 2
2.divide a number by 2 and round it down.
output the number of operations make them equal.
thinking of problem solving:for each number,move it continuously until it reaches 0,and record each numbers in the middle.If there is an odd number,multiply it to the max and record it.
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=1e5+5,inf=0x3f3f3f3f;
int n,m,cnt;
int a[maxn],mm,b[maxn],sum[maxn];
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
mm=max(mm,a[i]);
}
for(int i=1;i<=n;i++){
int x=a[i];
int step=0,k=0,y=0,res=-1;
while(x){
if(res==0){
b[x]++;
sum[x]+=step;
res=x&1;
x/=2;
step++;
}
else{
y=x;
k=0;
while(y<=mm){
b[y]++;
sum[y]+=step+k;
k++;
y*=2;
}
res=x&1;
x/=2;
step++;
}
}
}
int ans=inf;
for(int i=1;i<=mm;i++){
// printf("x = %d\n",sum[i]);
if(b[i]>=n)ans=min(ans,sum[i]);
}
cout<<ans;
}
9.CF25C Roads in Berland
Main idea:in the process of adding edges,output the sum of shortest path of all vertex.
Thinking of problem solving:Floyd
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=305,inf=0x3f3f3f3f;
int dis[maxn][maxn],n,m,q;
signed main(){
cin>>n;
memset(dis,inf,sizeof dis);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>dis[i][j];
}
}
cin>>q;
int res=0;
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
res+=dis[i][j];
}
}
for(int x=1;x<=q;x++){
int u,v,w;
cin>>u>>v>>w;
if(dis[u][v]>w)dis[u][v]=dis[v][u]=w;
else{
cout<<res<<" ";
continue;
}
for(int k=1;k<=n;k++){
if(k!=u&&k!=v)continue;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
}
}
res=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
res+=dis[i][j];
}
}
cout<<res<<" ";
}
return 0;
}
10.CF711D Directed Roads
Main idea:assign a direction of all edges,how many ways can I get rid of loops.
Thinking of problem solving:because there are only n edges and vertex,we can konw that must be a functional graph,in each loops,there are just two ways to make it a loop.According to the principle of multiplication,we can calculate the final formula:
a i a_i ai:edges in each loops
a n s = ans= ans= 2 n − ∑ a i 2^{n-\sum_{ }a_i} 2n−∑ai ∗ * ∗ ∏ 2 a i − 2 \prod_{}2^{a_i}-2 ∏2ai−2
#include<bits/stdc++.h>
#define int long long
using namespace std;
constexpr int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
int n,m,du[maxn],vis[maxn],f[maxn];
int res,ans=1;
vector<int>e[maxn];
map<pair<int,int>,int>mp;
inline int ksm(int a,int b){
int k=1;
while(b){
if(b&1)k=k*a%mod;
a=a*a%mod;
b>>=1;
}
return k;
}
void topo(){
queue<int>q;
for(int i=1;i<=n;i++){
if(du[i]==1){
q.push(i);
vis[i]=i;
}
}
while(!q.empty()){
int u=q.front();
q.pop();
for(auto v:e[u]){
du[v]--;
if(du[v]<=1&&!vis[v]){
vis[v]=v;
q.push(v);
}
}
}
}
void dfs(int u,int fa){
vis[u]=fa;
f[fa]++;
for(auto v:e[u]){
if(!vis[v]&&du[v]>1){
dfs(v,fa);
}
}
}
signed main(){
cin>>n;
int flag=0;
for(int i=1;i<=n;i++){
int x;
cin>>x;
e[i].emplace_back(x);
e[x].emplace_back(i);
du[i]++;
du[x]++;
}
topo();
for(int i=1;i<=n;i++){
if(!vis[i]&&du[i]>1){
dfs(i,i);
}
}
for(int i=1;i<=n;i++){
if(vis[i]==i&&f[i]==0){
res++;
// printf(" f = %d i = %d,\n" ,f[i],i);
}
else if(vis[i]==i&&f[i]>1){
// printf(" f = %d i = %d,\n" ,f[i],i);
ans=ans*(ksm(2,f[i])-2)%mod;
}
}
cout<<ans*ksm(2,res)%mod;
}