A. Median of an Array
题意:
题目链接:https://codeforces.com/contest/1946/problem/A
题解:首先得到中位数的位置,本来直接加一就可以,但如果后面还有和该位置数相同的数,这个位置的值加一后会被换到后面去,所以所需的操作次数就是这个数及其后面与该数相同的数。
代码:
#include <iostream>
#include<algorithm>
using namespace std;
const int N = 1e5+7;
int a[N];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--) {
int n;
cin >> n;
for(int i = 1;i <= n;i++) cin>>a[i];
sort(a,a+1+n);
int num = 0;
int i = (n+1)/2;
while(i<=n&&a[i]<=a[(n+1)/2]) {
num++;
i++;
}
cout<<num<<endl;
}
return 0;
}
B. Maximum Sum
题意:
题目链接:https://codeforces.com/contest/1946/problem/B
题解:首先肯定是找到数组中的最大子段和,如果最大子段和小于等于0的话,那么k次操作实际上都是选择插入零数组,k次后数组和仍为原数组和sum;如果最大子段和大于0的话,每一次操作肯定选择将其和插入到最大子段当中,这样最大子段和能成倍增加,假设初始数组的最大子段和为res,第一次操作后数组和为sum+res,第二次操作后数组和为sum+3res,第三次操作后数组和为sum+7res,以此类推,第k次操作后数组和为sum+(2k-1)*res,其中2k可以用快速幂取模计算,最后答案记得取模。
代码:
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 2e5+7;
ll a[N];
const long long p = 1e9+7;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;cin>>t;
while(t--) {
ll n,k;
cin >> n >> k;
ll sum = 0;
for(int i = 1;i<=n;i++) cin >> a[i],sum+=a[i];
ll ans = 0;
ll res = -1e10;
for(int i = 1;i<=n;i++) {
if(ans>=0) ans += a[i];
else ans = a[i];
res = max(res,ans);
}
if(res<=0) {
sum = (sum % p + p)%p;
}
else {
ll di = 2;
ll da = 1;
while(k) {
if(k&1) da = (da%p * di%p)%p;
k >>= 1;
di = (di%p * di%p) % p;
}
ll tmp = res;
res = (res%p * da%p)%p;
sum = (sum%p + res%p)%p;
sum = ((sum%p-tmp%p)%p+p)%p;
}
cout << sum << endl;
}
return 0;
}
C. Tree Cutting
题意:
大致意思就是删除树的k条边,然后树被分为了k+1个部分,要求最小的部分包含的节点个数尽可能大。
题目链接:https://codeforces.com/contest/1946/problem/C
题解:要求最小的部分包含的节点个数尽可能大,一眼二分,二分最小部分节点个数x,然后验证能否将原树划分为k+1个部分,最小部分节点个数大于等于x。怎么验证呢?用dfs,我们可以取1为根节点挂起这棵树,从1号节点开始dfs,在返回过程中统计该节点及子树大小,如果大于等于x,则sum++(sum为切的刀数),同时返回给父节点的个数为0,如果小于x,则正常返回大小。最后比较sum和k的关系,如果sum>k,则说明x可行,代码如下:
题外话:最先开始我的做法是先求出每个节点及其子树大小,然后再dfs,然后wa了,最后发现是因为dfs逻辑问题,当我dfs到一个节点后,代码逻辑是如果该节点有子节点被割掉了,那么该节点向上返回丢失的节点数,但其实还应该判断一下该节点是否会被割掉,不会被割掉才向上返回丢失的节点数。
代码:
#include <iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 1e5+7;
vector<int> e[N];
int vis[N];
int num[N];
int n,k;
int sum = 0;
int dfs(int u,int x) {
//cout << "? " << u << endl;
vis[u] = 1;
num[u] = 1;
for(int v:e[u]) {
if(!vis[v]) num[u] += dfs(v,x);
}
//cout<< x<<" " <<u << " " <<num[u] << endl;
if(num[u]>=x) {sum++;return 0;}
else return num[u];
}
bool check(int i) {
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
sum = 0;
dfs(1,i);
if(sum>k) return 1;
else return 0;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--) {
cin >> n >> k;
int u,v;
for(int i = 1; i < n; i++) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
//calnum(1);
//cout<<"hello"<<endl;
//memset(vis,0,sizeof(vis));
int l = 1,r = n;
while(l<=r) {
int mid = (l+r)>>1;
//memset(vis,0,sizeof(vis));
if(check(mid)) l = mid + 1;
else r = mid - 1;
}
cout << r << endl;
for(int i = 1;i<=n;i++) e[i].clear();
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
}
return 0;
}