A. Median of an Array
签到。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<int, 3> ar;
int mod = 1e9+7;
// const int maxv = 4e6 + 5;
// #define endl "\n"
void solve()
{
int n;
cin>>n;
vector<int> a(n+5);
for(int i=1;i<=n;i++) cin>>a[i];
sort(a.begin()+1,a.begin()+1+n);
int pos=(n+1)/2;
int cnt=1;
for(int i=pos+1;i<=n;i++){
if(a[i]==a[pos]) cnt++;
}
cout<<cnt<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
B. Maximum Sum
思路:找到最大非负子段和,然后不停的插进去,设第一次取的最大子段和为
s
s
s,那么第二次插入的为原本的最大子段和加上第一次插入的最大子段和,总共为
2
×
s
2\times s
2×s,依次类推,后续插入的为
4
×
s
4\times s
4×s,最终为
2
n
×
s
2^n\times s
2n×s
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<int, 3> ar;
int mod = 1e9+7;
// const int maxv = 4e6 + 5;
// #define endl "\n"
ll dp[N];
ll qmi(ll a,ll b,ll c)
{
ll res=1;
while(b){
if(b%2){
res=res*a%c;
}
b>>=1;
a=a*a%c;
}
return res;
}
void solve()
{
int n,k;
cin>>n>>k;
vector<ll> a(n+5);
ll ans=0;
for(int i=1;i<=n;i++) cin>>a[i],ans+=a[i];
memset(dp,-0x3f,sizeof dp);
ll res=-2e18;
for(int i=1;i<=n;i++) dp[i]=max(dp[i-1]+a[i],a[i]),res=max(res,dp[i]);
res=max(res,0ll);
ans+=res%mod*(qmi(2,k,mod)-1)%mod;
ans%=mod;
ans=(ans+mod)%mod;
cout<<ans<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
C. Tree Cutting
题意:给一颗树,要求将其砍成
k
−
1
k-1
k−1块,保证每块的大小至少为
x
x
x,求
x
x
x的最大值。
思路:砍树模板题,只不过从一根棍子变成了一颗树而已,显然对于连通块的大小具有单调性,当连通块大小比较小的时候,我们能砍出来的个数就比较多,反之,个数则越来越少。所以我们可以去二分连通块的大小,从而得到答案。
最近可能是写二分写迷糊了,对于二分答案的状态转移有点写不明白,因为是求连通块大小的最大值,所以其只能由小的状态进行转移,例如当我砍出了很多连通块,那么代表此时我连通块的大小过于小了,我还可以继续砍,一直砍到刚刚合法的状态为止。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<int, 3> ar;
int mod = 1e9+7;
// const int maxv = 4e6 + 5;
// #define endl "\n"
int n,k;
vector<int> e[N];
int sz,cnt;
void add(int u,int v)
{
e[u].push_back(v);
e[v].push_back(u);
}
int dfs(int u,int f)
{
int sum=1;
vector<int> c;
for(auto v: e[u]){
if(v==f) continue;
c.push_back(dfs(v,u));
}
for(auto y: c){
if(y>=sz) cnt++;
else{
sum+=y;
}
}
return sum;
}
bool check(int x)
{
sz=x,cnt=0;
if(dfs(1,-1)>=sz) cnt++;
return cnt<=k;
}
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++) e[i].clear();
for(int i=1;i<=n-1;i++){
int u,v;
cin>>u>>v;
add(u,v);
}
int l=1,r=n+5;
int ans=0;
while(l<=r){
int mid=(l+r)/2;
if(check(mid)){
r=mid-1;
ans=mid;
}
else{
l=mid+1;
}
}
cout<<ans-1<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
神奇状态转移的迷之代码