AtCoder Beginner Contest 160
A - Coffee
#include <bits/stdc++.h> #define ll long long using namespace std; char s[10]; int main() { //freopen("in.txt","r",stdin); scanf("%s",s); if(s[2]==s[3]&&s[4]==s[5]) printf("Yes\n"); else printf("No\n"); return 0; }
B - Golden Coins
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { //freopen("in.txt","r",stdin); ll x; scanf("%lld",&x); printf("%lld\n",x/500*1000+(x%500)/5*5); return 0; }
C - Traveling Salesman around Lake
题意:在一个周长为K的圆形中,有N个房子距离最北边的距离为Ai(顺时针),可以任意选一个房子作为起点,求访问完N个房子的最小距离。
数据范围:$2 \leq K \leq 10^{6},2 \leq N \leq 2 \times 10^{5}$
题解:最优解肯定是沿一个方向的,环形可以将原序列扩展一倍,遍历序列每一对下标相差N的位置的差值,最小值即为答案。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+5; int a[N<<1]; int main() { //freopen("in.txt","r",stdin); int k,n; scanf("%d%d",&k,&n); for(int i=0;i<n;i++) { scanf("%d",&a[i]); a[i+n]=a[i]+k; } int ans=1e9; for(int i=0;i<n;i++) { ans=min(ans,a[i+n-1]-a[i]); } printf("%d\n",ans); return 0; }
D - Line++
题意:给一个图,满足任意i=1,2,...,N-1,i和i+1有连边,且X和Y有连边,对于k=1,2,...,N-1,求最短距离为k的点对数量。
数据范围:$3 \leq N \leq 2\times 10^{3},X+1 < Y$
题解:暴力求每个点对的最短距离,要么就是i,j直达,要么就是i到X,X到Y,Y到j,取小即可。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=2e3+5; int a[N]; int main() { //freopen("in.txt","r",stdin); int n,x,y; scanf("%d%d%d",&n,&x,&y); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { int t=min(j-i,abs(i-x)+abs(j-y)+1); a[t]++; } } for(int i=1;i<n;i++) { printf("%d\n",a[i]); } return 0; }
E - Red and Green Apples
题意:给A个红苹果,B个绿苹果,C个无色苹果,每个苹果都有美味值,可以将无色苹果涂成任意颜色,求吃X个红苹果和Y个绿苹果的最大美味值。
数据范围:$1\leq X \leq A \leq 10^{5},1\leq Y \leq B \leq 10^{5},1\leq C \leq 10^{5}$
题解:按美味值降序,有色苹果能吃就吃并将X或Y减1,无色苹果直接吃,计数器加1,若计数器等于X+Y代表不能吃了,直接退出。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+5; struct P { int val,id; bool operator <(const P &t)const { if(val!=t.val) return val>t.val; return id<t.id; } }p[N*3]; int main() { //freopen("in.txt","r",stdin); int x,y,a,b,c; scanf("%d%d%d%d%d",&x,&y,&a,&b,&c); for(int i=0,d;i<a;i++) { scanf("%d",&d),p[i]={d,1}; } for(int i=0,d;i<b;i++) { scanf("%d",&d),p[i+a]={d,2}; } for(int i=0,d;i<c;i++) { scanf("%d",&d),p[i+a+b]={d,0}; } a=a+b+c; sort(p,p+a); ll ans=0; int t=0; for(int i=0;i<a;i++) { if(p[i].id==1) { if(x) x--,ans+=p[i].val; } else if(p[i].id==2) { if(y) y--,ans+=p[i].val; } else { t++,ans+=p[i].val; } if(t==x+y) break; } printf("%lld\n",ans); return 0; }
F - Distributing Integers
题意:给一棵N个节点的无根树,对于k=1,2,...,N,将1写在节点k上,然后2~n依次写在与有值的节点相邻的节点上,求最后有多少种写法。(对1e9+7取模)
数据范围:$2\leq N \leq 2 \times 10^{5}$
题解:问题其实就是以k为根节点的树的拓扑序列个数,设szi为i子树的大小,答案为$\frac{N!}{\prod sz_{i}}$。
首先1~N的全排列有N!种情况,对于每个节点x,x要在x子树的其它节点之前,相当于在之前的基础上除以szx。
考虑u,v相连,根节点从u转移到v的情况,可以发现只有szu和szv发生变化。那么可以先算出以1为根节点的个数,然后转移即可。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+5; const int MD=1e9+7; vector<int> G[N]; int f[N],ans[N]; int n,a,b; int quick_pow(int x,int y) { int ans=1; while(y) { if(y&1) ans=1LL*ans*x%MD; y>>=1; x=1LL*x*x%MD; } return ans; } void dfs(int u,int fa) { for(auto v:G[u]) { if(v==fa) continue; dfs(v,u); f[u]+=f[v]; } f[u]++; } void cal(int u,int fa) { for(auto v:G[u]) { if(v==fa) continue; ans[v]=1LL*ans[u]*quick_pow(f[v],MD-2)%MD*(n-f[v])%MD; cal(v,u); } } int main() { //freopen("in.txt","r",stdin); scanf("%d",&n); for(int i=1;i<n;i++) { scanf("%d%d",&a,&b); G[a].push_back(b); G[b].push_back(a); } dfs(1,-1); ans[1]=1; for(int i=1;i<=n;i++) { ans[1]=1LL*ans[1]*f[i]%MD; } cal(1,-1); int t=1; for(int i=1;i<=n;i++) t=1LL*t*i%MD; for(int i=1;i<=n;i++) { printf("%d\n",1LL*t*quick_pow(ans[i],MD-2)%MD); } return 0; }