Codeforces Round #485 (Div. 2)
Posted hdujackyan
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #485 (Div. 2)相关的知识,希望对你有一定的参考价值。
C.http://codeforces.com/contest/987/problem/C
题意:从左到右有n个显示器,每个显示器都有一个高度h[i]和一个费用val[i],现在从中选出三个显示器,满足i<j<k&&h[i]<h[j]<h[k],求需要的最少费用
分析:设置数组dp[maxn],保存长度为2的LIS的最小花费,dp[i]=min(val[k]+val[i]) (k<i&&h[k]<h[i]) ans=min(dp[k]+val[i]) (k<i&&dp[k]!=初始值)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int maxn=3010; 7 const int inf=1e9; 8 int h[maxn],val[maxn]; 9 struct node{ 10 int val1,val2; 11 }dp[maxn]; 12 13 int main() 14 { 15 int n,i,j,k,x,y,z,ans; 16 while ( scanf("%d",&n)!=EOF ) 17 { 18 for ( i=1;i<=n;i++ ) scanf("%d",&h[i]); 19 for ( i=1;i<=n;i++ ) scanf("%d",&val[i]); 20 ans=inf; 21 for ( i=1;i<=n;i++ ) 22 { 23 dp[i].val1=val[i]; 24 dp[i].val2=inf; 25 } 26 for ( i=1;i<=n;i++ ) 27 { 28 for ( j=1;j<i;j++ ) 29 { 30 if ( h[j]<h[i] ) 31 { 32 dp[i].val2=min(dp[i].val2,dp[j].val1+val[i]); 33 ans=min(ans,dp[j].val2+val[i]); 34 } 35 } 36 } 37 if ( ans==inf ) printf("-1 "); 38 else printf("%d ",ans); 39 } 40 return 0; 41 }
D.http://codeforces.com/contest/987/problem/D
题意:有n个仓市集,每个市集有一种特产,一共有k种特产,从一个市集可以移动到其他任意一个市集,路程是经过的边数。对于每个市集来说想要收集到k种不同的特产需要走的路程是多少
分析:因为k<=100,所以我们bfs考虑从特产数出发,设置d[i][k]表示第i个市集想要收集到第k个特产所需要的最少路程。对于每个特产单独bfs,最后对于每个市集收集不同特产的距离进行排序,取前s个
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 const int maxn=1e5+10; 8 const int maxm=110; 9 const int inf=1e9; 10 int d[maxn][maxm]; 11 vector<int>G[maxn]; 12 vector<int>E[maxn]; 13 int n,ans[maxn]; 14 15 void bfs(int x) 16 { 17 queue<int>que; 18 for ( int i=0;i<E[x].size();i++ ) 19 { 20 int u=E[x][i]; 21 d[u][x]=0; 22 que.push(u); 23 } 24 while ( !que.empty() ) 25 { 26 int u=que.front(); 27 que.pop(); 28 for ( int i=0;i<G[u].size();i++ ) 29 { 30 int v=G[u][i]; 31 if ( d[v][x]==inf ) 32 { 33 d[v][x]=d[u][x]+1; 34 que.push(v); 35 } 36 } 37 } 38 } 39 40 int main() 41 { 42 int m,k,s,i,j,x,y,z,u,v,sum; 43 while ( scanf("%d%d%d%d",&n,&m,&k,&s)!=EOF ) 44 { 45 for ( i=1;i<=n;i++ ) G[i].clear(); 46 for ( i=1;i<=k;i++ ) E[i].clear(); 47 for ( i=1;i<=n;i++ ) 48 { 49 for ( j=1;j<=k;j++ ) d[i][j]=inf; 50 } 51 for ( i=1;i<=n;i++ ) 52 { 53 scanf("%d",&x); 54 E[x].push_back(i); 55 } 56 for ( i=1;i<=m;i++ ) 57 { 58 scanf("%d%d",&u,&v); 59 G[u].push_back(v); 60 G[v].push_back(u); 61 } 62 for ( i=1;i<=k;i++ ) bfs(i); 63 for ( i=1;i<=n;i++ ) 64 { 65 sort(d[i]+1,d[i]+1+k); 66 sum=0; 67 for ( j=1;j<=s;j++ ) sum+=d[i][j]; 68 ans[i]=sum; 69 } 70 for ( i=1;i<=n;i++ ) 71 { 72 printf("%d",ans[i]); 73 if ( i!=n ) printf(" "); 74 else printf(" "); 75 } 76 } 77 return 0; 78 }
E.http://codeforces.com/contest/987/problem/E
以下分析来自:https://blog.csdn.net/Stupid_Turtle/article/details/80514590
题意:Petr和Alex两个人对一个初始为1,2,3,...,n的长度为n的排列有不同的操作次数(一次操作表现为将其中两个数交换位置,比如1,2,3,4变为1,2,4,3称为一次操作),Petr会对其进行3n次操作,而Alex会对其进行7n+1次操作。现在给你初始排列的长度n和结果排列,问你是他们中的谁进行的操作,如果是Petr输出"Petr",否则输出"Um_nik"。
分析:利用到排列的性质:对于一个排列,他所包含的逆序数的对数称为它的逆序数,逆序数为奇数的排列称为奇排列,逆序数为偶数的排列称为偶排列,调换一个奇排列中两个数的位置可以把它变成偶排列,同样,调换一个偶排列中的两个数的位置可以把他变成奇排列。
那么显然,初始排列1,2,...,n的逆序数为0,这样只要求出结果排列的逆序数就可以知道到底进行了奇数次还是偶数次操作。而当n为奇数的时候,3n为奇,7n+1为偶;当n为偶数的时候,3n为偶,7n+1为奇。那么根据n的奇偶性和结果逆序数的奇偶性,就可以知道是谁进行的操作。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 typedef long long ll; 6 const int maxn=1e6+10; 7 ll bit[maxn]; 8 ll n,a[maxn]; 9 10 ll lowbit(ll x) 11 { 12 return x&(-x); 13 } 14 15 void add(ll k) 16 { 17 while ( k<=n ) 18 { 19 bit[k]++; 20 k+=lowbit(k); 21 } 22 } 23 24 ll sum(ll k) 25 { 26 ll s=0; 27 while ( k ) 28 { 29 s+=bit[k]; 30 k-=lowbit(k); 31 } 32 return s; 33 } 34 35 int main() 36 { 37 ll m,i,j,k,x; 38 ll ans; 39 while ( scanf("%lld",&n)!=EOF ) 40 { 41 memset(bit,0,sizeof(bit)); 42 ans=0; 43 for ( i=1;i<=n;i++ ) 44 { 45 scanf("%lld",&x); 46 add(x); 47 ans+=(i-sum(x)); 48 } 49 if ( n%2 == ans%2 ) printf("Petr "); 50 else printf("Um_nik "); 51 } 52 return 0; 53 }
F.http://codeforces.com/contest/987/problem/F
题意:给出m个数,对于某两个数x,y,如果有x&y==0,那么在x和y之间连一条边,先求有几个连通块
分析:对于某个数x,只有当x和y的二进制含1的位置不同才能连一条边。考虑搜索,所有数的最大值为A=(1<<n)-1。对于x,考虑x^A(op==1,op=0表示第一次dfs)及其子集(去掉其中的部分1,一次dfs可以去掉二进制中的一个1)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int maxn=(1<<22)+5; 6 int a[maxn],n,m,A; 7 bool vis[maxn],have[maxn]; 8 9 void dfs(int u,int op) 10 { 11 vis[u]=true; 12 if ( !vis[u^A] && have[u] ) dfs(u^A,1); 13 if ( op==0 ) return; 14 for ( int i=0;i<n;i++ ) 15 { 16 if ( u&(1<<i) ) 17 { 18 int v=u^(1<<i); 19 if ( !vis[v] ) dfs(v,1); 20 } 21 } 22 } 23 24 int main() 25 { 26 int i,j,k,x,y,z,u,v,ans; 27 while ( scanf("%d%d",&n,&m)!=EOF ) 28 { 29 memset(vis,false,sizeof(vis)); 30 memset(have,false,sizeof(have)); 31 for ( i=1;i<=m;i++ ) 32 { 33 scanf("%d",&a[i]); 34 have[a[i]]=true; 35 } 36 A=(1<<n)-1; 37 ans=0; 38 for ( i=1;i<=m;i++ ) 39 { 40 if ( !vis[a[i]] ) 41 { 42 dfs(a[i],0); 43 ans++; 44 } 45 } 46 printf("%d ",ans); 47 } 48 return 0; 49 }
以上是关于Codeforces Round #485 (Div. 2)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #485 (Div. 2) C. Three displays
Codeforces Round #485 (Div. 2) E. Petr and Permutations
Codeforces Round #485 (Div. 2) C Three displays