A.最小生成树
思路:贪心。
显然对于一个个结点的无向完全图,要想使其成为一棵树,我们只需选取条边,总贡献是
我们所有结点至少被加一次,所以剩下个结点是要重复加的,显然用点权最小的结点重复即可。所以排个序就解决了。
时间复杂度:
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7; #define mst(a) memset(a,0,sizeof a) #define lx x<<1 #define rx x<<1|1 #define reg register #define PII pair<int,int> #define fi first #define se second int a[N]; int main(){ int n; scanf("%d",&n); ll ans=0; for(int i=1;i<=n;i++) scanf("%d",&a[i]); sort(a+1,a+n+1); for(int i=2;i<=n;i++) ans+=a[1]+a[i]; printf("%lld\n",ans); return 0; }
B.病毒感染
思路:树的重心。
显然根据树的重心性质可知,到所有结点距离和最小的结点是树的重心。
接下用求出无根树的树的重心即可, 需要注意的是树的重心可能不止一个。
时间复杂度:
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e4+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7; #define mst(a) memset(a,0,sizeof a) #define lx x<<1 #define rx x<<1|1 #define reg register #define PII pair<int,int> #define fi first #define se second int sz[N],mn=inf,n,m; vector<int>ans,e[N]; void dfs(int u,int fa){ sz[u]=1; int mx=0; for(auto v:e[u]){ if(v==fa) continue; dfs(v,u); sz[u]+=sz[v]; mx=max(mx,sz[v]); } mx=max(mx,n-sz[u]); if(mx<mn){ ans.clear(); mn=mx; ans.push_back(u); } else if(mx==mn) ans.push_back(u); } int main(){ scanf("%d%d",&n,&m); for(int i=1,u,v;i<=m;i++){ scanf("%d%d",&u,&v); e[u].push_back(v),e[v].push_back(u); } dfs(1,0); for(auto i:ans) printf("%d ",i); puts(""); return 0; }
C.Shopping
思路:贪心。
显然我们可以知道,如果我们当前有个凳子,说明我们可以使个物品变成半价,所以根据贪心,我们可以取最大的个半价算,然后其他按原价算即可。
时间复杂度:
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e3+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7; #define mst(a) memset(a,0,sizeof a) #define lx x<<1 #define rx x<<1|1 #define reg register #define PII pair<int,int> #define fi first #define se second vector<int>e[N],b; int c[N]; int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); b.clear(); for(int i=1,y;i<=n;i++){ scanf("%d%d",&c[i],&y); if(y==1) b.push_back(c[i]); } sort(c+1,c+n+1,greater<int>()); int cnt=min((int)b.size(),m); double ans=0; for(int i=1;i<=cnt;i++) ans+=(double)c[i]/2.0; for(int i=cnt+1;i<=n;i++) ans+=c[i]; printf("%.1lf\n",ans); } return 0; }
D.铺地毯
思路:暴力。
因为题目有后来的地毯覆盖先前的地毯的性质,所以我们可以顺序遍历即可。
时间复杂度:
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e4+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7; #define mst(a) memset(a,0,sizeof a) #define lx x<<1 #define rx x<<1|1 #define reg register #define PII pair<int,int> #define fi first #define se second struct node{ int a,b,g,k; }A[N]; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d%d%d",&A[i].a,&A[i].b,&A[i].g,&A[i].k); } int x,y; int ans=-1; scanf("%d%d",&x,&y); for(int i=1;i<=n;i++){ if(x>=A[i].a&&x<=A[i].a+A[i].g&&y>=A[i].b&&y<=A[i].b+A[i].k) ans=i; } printf("%d\n",ans); return 0; }
E.金币馅饼
思路:。
显然根据题目我们可以知道对于当前状态可以由递推过来。
所以状态转移方程是:
注意初始化,将不能走到的点保持为。
时间复杂度:
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=305+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7; #define mst(a) memset(a,0,sizeof a) #define lx x<<1 #define rx x<<1|1 #define reg register #define PII pair<int,int> #define fi first #define se second int dp[N][N]; int a[N][N]; int main(){ int r,c; scanf("%d%d",&r,&c); memset(dp,-1,sizeof dp); for(int i=1;i<=r;i++) for(int j=1;j<=c;j++) scanf("%d",&a[i][j]); dp[1][1]=a[1][1]; for(int j=1;j<=c;j++) for(int i=1;i<=r;i++){ for(int k=max(1,i-1);k<=min(r,i+1);k++){ if(dp[k][j-1]!=-1) dp[i][j]=max(dp[i][j],a[i][j]+dp[k][j-1]); //printf("dp[%d][%d]=%d\n",i,j,dp[i][j]); } } printf("%d\n",dp[r][c]); return 0; }