暴力贪心,对于相邻的两个数字a[i]和a[i+1]如果a[i]>a[i+1]那么最少需要a[i]次操作才可以让a[i]<=a[i+1],那么对于所有的这样的a[i]选择最大的即可
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) a.begin(),a.end()
#define fr(a,i,n) for(int i=a;i<=n;i++)
#define fe(a,i,n) for(int i=n;i>=a;i--)
#define fcf(i,cur) for(int i=cfs.h[cur],sup=cfs.e[i];i;i=cfs.net[i],sup=cfs.e[i])
#define endl "\n"
istream &operator>>(istream &in,pii &a){return in>>a.first>>a.second;};
ostream &operator<<(ostream&,pii &a){return cout<<a.first<<' '<<a.second;};
template<typename T>
istream &operator>>(istream &in,vector<T>&v){T x;in>>x;v.push_back(x);return in;};
string YES="YES",Yes="Yes",yes="yes",NO="NO",No="No",no="no";
const int N=2e5+10,M=1e6+10,mod=1e9+7;
string s;
int n,m,k;
int a[N];
void solve(){
cin>>n;
fr(1,i,n)cin>>a[i];
int ans=0;
fr(2,i,n){
if(a[i-1]>a[i])ans=max(ans,a[i-1]);
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(false);
int t=1;
cin>>t;
fr(1,i,t){
solve();
}
}
也是一个贪心的思想,对于a[i]为1的时候a[i]最少为2,否则最小为1,如果所有的拿最小要超过数组a所有元素的和的话,那么就肯定是不可能的了,否则多余的可以全部放到a[i]上.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) a.begin(),a.end()
#define fr(a,i,n) for(int i=a;i<=n;i++)
#define fe(a,i,n) for(int i=n;i>=a;i--)
#define fcf(i,cur) for(int i=cfs.h[cur],sup=cfs.e[i];i;i=cfs.net[i],sup=cfs.e[i])
#define endl "\n"
istream &operator>>(istream &in,pii &a){return in>>a.first>>a.second;};
ostream &operator<<(ostream&,pii &a){return cout<<a.first<<' '<<a.second;};
template<typename T>
istream &operator>>(istream &in,vector<T>&v){T x;in>>x;v.push_back(x);return in;};
string YES="YES",Yes="Yes",yes="yes",NO="NO",No="No",no="no";
const int N=2e5+10,M=1e6+10,mod=1e9+7;
string s;
int n,m,k;
int a[N];
void solve(){
cin>>n;
fr(1,i,n)cin>>a[i];
ll sum=0;
fr(1,i,n)sum+=a[i];
ll cnt=0;
fr(1,i,n)if(a[i]==1)cnt++;
if(n==1||cnt*2+(n-cnt)>sum){
cout<<NO<<endl;
// return ;
}else{
cout<<YES<<endl;
}
}
int main(){
ios::sync_with_stdio(false);
int t=1;
cin>>t;
fr(1,i,t){
solve();
}
}
二分答案
对于每个位置都二分在k次操作下能够选定的最大值,对于第i个位置假设一定是最大值的话,会出现a[i]=x,a[i+1]=x-1,a[i+2]=x-2,然后到某一个并不需要操作的位置j停止,
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) a.begin(),a.end()
#define fr(a,i,n) for(int i=a;i<=n;i++)
#define fe(a,i,n) for(int i=n;i>=a;i--)
#define fcf(i,cur) for(int i=cfs.h[cur],sup=cfs.e[i];i;i=cfs.net[i],sup=cfs.e[i])
#define endl "\n"
istream &operator>>(istream &in,pii &a){return in>>a.first>>a.second;};
ostream &operator<<(ostream&,pii &a){return cout<<a.first<<' '<<a.second;};
template<typename T>
istream &operator>>(istream &in,vector<T>&v){T x;in>>x;v.push_back(x);return in;};
string YES="YES",Yes="Yes",yes="yes",NO="NO",No="No",no="no";
const int N=2e5+10,M=1e6+10,mod=1e9+7;
string s;
ll n,m,k;
ll a[N];
int check(ll x,ll inx){
ll cnt=0;
fr(inx,i,n){
ll cur=x-(i-inx);
if(a[i]>=cur)return 1;
cnt+=cur-a[i];
if(cnt>k)return 0;
}
if(a[n]<x-(n-inx))return 0;
return 1;
}
void solve(){
cin>>n>>k;
fr(1,i,n)cin>>a[i];
ll ans=a[1];
fr(1,i,n){
ll l=ans,r=a[i]+k;
while(l<=r){
ll mid=(l+r)>>1;
if(check(mid,i)){
l=mid+1;
}else{
r=mid-1;
}
}
ans=max(ans,l-1);
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(false);
int t=1;
cin>>t;
fr(1,i,t){
solve();
}
}
分治
对于一个区间两个区间[l,mid],[mid+1,r]假设我都已经知道了最大值的位置inx1和inx2,如何去计算inx1和inx2那个更加的大呢?,如果假设inx1是最大的那么询问的区间[inx1,inx2]包含inx1和不包含inx1产生的差值一定是inx2-inx1,因为如果inx1是最大的那么对于区间[inx1+1,inx2]内所有的元素都会产生一个逆序对,数量刚好是inx2-inx1,通过分治从小区间开始计算出每个区间的最大值,每次的花费都不超过2*len^2,最终的花费不会超过3*n^2
还有就是一点点小细节
这两个写法好像是一样的,对于后面这个cf的判题机是直接输出"! "后继续计算,而不是递归结束后统一输出,就会变成这样,被编译器坑了
多重背包+bitset优化
很容易发现其实最终是解决一个这样的问题:对于每个节点假设他有m个子节点,第i个子节点所在子树的节点数量为a[i]那么就是将这m个子节点分成两份,使得这两份子节点的数量和的乘积最大
对于每个节点i假设节点i所在子树除了i以外的节点数量为sum,要取得乘积的最大值那么分成两份的和a,b(a+b=sum),其中a或b要尽可能的靠近sum/2,这样a*b的值才能最大,很显然是一个背包问题,计算过程中会出现非常多的重复元素,所以使用多充背包再结合bitset优化.
其中bitset优化的时候开的size大小肯定是大于sum,然后越小越好,bitset不支持变量定义大小,就需要运用一定的小技巧(题解学的)
倍增为大于sum的最小的2^k
最终的复杂度为nsqrt(n) 本人比较的菜,无法给出证明
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define all(a) a.begin(),a.end()
#define fr(a,i,n) for(int i=a;i<=n;i++)
#define fe(a,i,n) for(int i=n;i>=a;i--)
#define fcf(i,cur) for(int i=cfs.h[cur],sup=cfs.e[i];i;i=cfs.net[i],sup=cfs.e[i])
#define endl "\n"
istream &operator>>(istream &in,pii &a){return in>>a.first>>a.second;};
ostream &operator<<(ostream&,pii &a){return cout<<a.first<<' '<<a.second;};
template<typename T>
istream &operator>>(istream &in,vector<T>&v){T x;in>>x;v.push_back(x);return in;};
string YES="YES",Yes="Yes",yes="yes",NO="NO",No="No",no="no";
const int N=1e6+10,M=2e6+10,mod=1e9+7;
string s;
int n,m,k;
vector<int>e[N];
vector<int>v;
int vis[N],son[N];
struct CFS{
int h[N]={0},e[M]={0},v[M]={0},net[M]={0},top=0;
void add(int a,int b){
top++;
e[top]=b;
net[top]=h[a];
h[a]=top;
return ;
}
void add(int a,int b,int c){
top++;
e[top]=b;
v[top]=c;
net[top]=h[a];
h[a]=top;
return ;
}
void init(int n){
top=0;
fr(1,i,n)h[i]=0;
}
}cfs;
template<int siz=1>
ll run(int len){
if(v.size()<=1)return 0;
if(siz<=len)return run<min(siz*2,N-1)>(len);
bitset<siz>dp;
dp[0]=1;
for(auto inx:v)dp|=(dp<<inx);
fe(0,i,len)if(dp[i])return i;
}
ll ans;
void dfs(int cur){
int mx=0;
fcf(i,cur){
dfs(sup);
son[cur]+=son[sup];
mx=max(mx,son[sup]);
}
if(mx>=son[cur]/2){
ans+=1LL*mx*(son[cur]-mx);
son[cur]++;
return ;
}
v.clear();
vector<int>tmp;
fcf(i,cur){
if(!(vis[son[sup]]++))tmp.push_back(son[sup]);
}
for(auto inx:tmp){
int cnt=1;
while(vis[inx]){
v.push_back(min(cnt,vis[inx])*inx);
vis[inx]-=min(vis[inx],cnt);
cnt*=2;
}
}
ll res=run(son[cur]/2);
ans+=res*(son[cur]-res);
son[cur]++;
}
void solve(){
cin>>n;
fr(2,i,n){
int a;
cin>>a;
cfs.add(a,i);
}
dfs(1);
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
// cin>>t;
fr(1,i,t){
solve();
}
}