总结:
这一场过了A题,之前用C++各种写,但是没想到用py三行代码就解决了问题,还是需要学习很多很多。
K
题意
土拨鼠在第1个宿舍,橙子在第n个宿舍。这n个宿舍间有n-1条路并且长度都为1,土拨鼠从第1个房间去第n个宿舍,速度为1m/s;橙子从第n个宿舍追赶土拨鼠,速度为2m/s。。
思路
二分时间 t ,然后判断在 ts 内土拨鼠是否会被橙子追上。以橙子所在的寝室 n 为根建树,从 1 到 n 枚举所有土拨鼠能够到达的点,先找出t秒能走到哪个点,然后再找这个点能走到的离n最远的点,判断在走的过程中会不会被追上。
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
vector<int> vv[maxn];
int vis[maxn];
int f[maxn];
int dep[maxn];
void dfs(int x,int fa,int de)
{
f[x] = fa;
dep[x] = de;
for (int i =0 ; i< vv[x].size(); i ++ )
{
int v = vv[x][i];
if(v == fa)
continue;
dfs(v,x,de + 1);
vis[x] |= vis[v];
}
}
int ans =0 ;
void dfs2(int x,int fa,int de)
{
ans = max(ans,de);
for (int i =0 ; i<vv[x].size(); i ++ )
{
int v = vv[x][i];
if(v == fa)
continue;
dfs2(v,x,de + 1);
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for (int i = 1; i < n; i ++ )
{
int x,y;
scanf("%d%d",&x,&y);
vv[x].push_back(y);
vv[y].push_back(x);
}
vis[1] = 1;
dfs(n,0,1);
int k = -1;
int s = dep[1] - m;
for (int i = 1; i <= n; i ++ ){
if(vis[i] && dep[i] == s){
k = i;
break;
}
}
int num = dep[k] - 1;
dfs2(k,f[k],1);
ans -- ;
num += ans;
int r = (num + 1) / 2;
int l = 0;
while(l < r){
int mid = l + r>> 1;
int x = min(2 * mid,num);
int y = min(mid, ans);
if(x - dep[k] + 1>= y) r = mid;
else l = mid + 1;
}
printf("%d\n",l);
}
F
题意
土拨鼠要和苹果约会,第 i 天它的第 j 件衣服的邋遢度为 aij ,它要在n天中选择m天和苹果约会,要求选出的m天衣服的邋遢度的最大值和最小值的差值最小。
思路
因为要最小化最大值和最小值的差值,所以用pair存每件衣服的邋遢度和第几天,然后对邋遢度从小到大排序。那么问题就转换成了求一个区间 [L,R] ,使得这个区间覆盖m个不同的天,并且R的邋遢度-L的邋遢度最小。这个问题就可以用尺取解决了。对于每一个L,求出最小的合法的R,每次更新差值最小值即可。
代码
#include<bits/stdc++.h>
#define st first
#define sd second
#define ll long long
#define pii pair<int,int>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2e6+10;
pii pp[maxn];
int vis[maxn];
int main()
{
int n,m;
scanf("%d%d",&n,&m);
int cnt = 0;
for (int i = 1; i <= n; i ++ ){
int p;
scanf("%d",&p);
for (int j = 1; j <= p; j ++ ){
int x;
scanf("%d",&x);
pp[++cnt].st = x;
pp[cnt].sd = i;
}
}
sort(pp + 1, pp + 1 + cnt);
int num = 0;
int l = 1, r = 1;
int minn = pp[1].st, maxx = 0;
int ans = inf;
while(1){
while(r <= cnt && num < m){
if(vis[pp[r].sd] == 0) num ++ ;
vis[pp[r].sd] ++ ;
maxx = pp[r].st;
r ++ ;
}
if(num < m)
break;
ans = min(ans, maxx - minn);
vis[pp[l].sd] -- ;
if(vis[pp[l].sd] == 0) num -- ;
minn = pp[l + 1].sd;
l ++ ;
}
printf("%d\n",ans);
}
I
题意
给出n个数(0<=a[i]<=9),由这n个数组成2个数,使得这两个数的乘积最小。
思路
自己造几个例子就可以看出,选择0之外最小的数和剩下的数字组成的没有前导0的数相乘结果最小。剩下的数字怎样最小呢,当然是找到最小的非零的数做第一位,后边接上所有的0,再按照有小到大的顺序放剩下的数字。因为n的范围在1e5,所以要用高精度乘法。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[100100];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
sort(a,a+n);
int k=0;
while(k<n&&a[k]==0) k++;
vector<int>q;
q.push_back(a[k+1]);
for(int i=0;i<k;i++) q.push_back(0);
for(int i=k+2;i<n;i++) q.push_back(a[i]);
vector<int>ans;
for(int i=q.size()-1;i>=0;i--){
int x=q[i]*a[k];
ans.push_back(x);
}
for(int i=0;i<10;i++) ans.push_back(0);
for(int i=0;i<ans.size();i++){
if(ans[i]>=10){
ans[i+1]+=ans[i]/10;
ans[i]%=10;
}
}
while(!ans.back()) ans.pop_back();
for(int i=ans.size()-1;i>=0;i--) cout<<ans[i];
cout<<endl;
}
return 0;
}