题解:P10971 Cookies
hgckythgcfhk · · 题解
提供一个能卡过,甚至能到最优解,不用 dp 的暴力乱搞做法。
其他题解说的很清楚了,每个人分配到的饼干个数随
下面我默认先强制给每个人分一个然后令
我们先按
1. 所有人可以分配一样多
这种情况显然答案为
2. 一共有两种不同个数
当
考虑满足不这个条件的
这样,我们把
3. 一共有 3 种不同个数
不难发现,把最小的个数全都清零分配到大的从而多造几个最大值显然更优,所以最小值一定是
另外考虑到一些奇怪的奇偶性和边界的问题,次大值可能不止一个,但最多有两个,这个结论我没证出来,但我经过了又臭又长的巨型分讨后证明了在数据范围内是成立的,所以我们要把有一个次大值和两个的情况分别枚举。
分析一下时间复杂度,最后一种情况是瓶颈,所以只分析这一种就行,我们要枚举有多少个最大值这个是
关于正确性,我有一个很长的证明,但考虑到这个构造比较自然,而且证明太过麻烦,所以不放了,我希望看到一个简洁的证明或者证伪,不过,即使你 hack 掉了我次大值最多两个的情况,我再多枚举一个次大值的个数只会使时间复杂度多带一个 hack 掉我不同个数不超过
说句闲话,如果你不判次大值有两个可以拿到
截至到现在:
最优解时间
正解最优时间
#include <bits/stdc++.h>
#define il inline
#define rg register
#define cit const rg unsigned
#define open ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)//,freopen("1.in","r",stdin),freopen("1.out","w",stdout)
#define int rg unsigned
#define void il void
#define ll long long
#define ull unsigned ll
#define vector basic_string
#define vint vector<unsigned>
#define sca(a) for(int $=0;$<n;cin>>a[++$])using namespace std;constexpr unsigned N=30+1;
unsigned n,m,a[N],id[N],ans[N],b[N];
void init(){sca(a);
for(int i=1;i<=n;++i)id[i]=i;
for(int i=1;i<=n;++i)
for(int j=1;j<n;++j)
if(a[id[j+1]]>a[id[j]])swap(id[j],id[j+1]);
}
void solve(){cin>>n>>m;m-=n;init();
if(m%n==0){cout<<"0\n";
for(int i=1;i<=n;++i)cout<<m/n+1<<' ';
return;
}if(m%(n-1)<=m/(n-1)){
ans[id[n]]=m%(n-1);int cnt=0;
for(int i=1;i<n;++i)ans[id[i]]=m/(n-1);
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(ans[j]>ans[i])cnt+=a[i];
cout<<cnt<<'\n';for(int i=1;i<=n;++i)cout<<ans[i]+1<<' ';
return;
}if(n==2){cout<<a[id[1]]<<'\n';
ans[id[1]]=m,ans[id[2]]=0;
cout<<ans[1]<<' '<<ans[2];return;
}int ll cnt=0;
for(int l=n-2,r=n;l;--l,--r){
for(int i=0;i<m;++i){
cit t=m-i,tl=t/l,tr=(t-tl*l)/(n-r+1);
if(((tl*l+i+tr*(n-r+1))^m)||i<tr||i>tl)continue;
ans[id[l+1]]=i;
for(int j=1;j<=l;++j)ans[id[j]]=tl;
for(int j=n;j>=r;--j)ans[id[j]]=tr;
for(int j=l+1;j<=n;++j){
if(ans[id[l]]>ans[id[j]])cnt+=a[id[j]]*l;
if(ans[id[l+1]]>ans[id[j]])cnt+=a[id[j]];
}l=1;break;
}
}for(int l=n-3,r=n;l;--l,--r){
for(int i=0;i+i<m;++i){
cit t=m-i-i,tl=t/l,tr=(t-tl*l)/(n-r+1);
if(((tl*l+i+i+tr*(n-r+1))^m)||i<tr||i>tl)continue;
b[id[l+1]]=i;b[id[l+2]]=i;
for(int j=1;j<=l;++j)b[id[j]]=tl;
for(int j=n;j>=r;--j)b[id[j]]=tr;int ll _=0;
for(int j=l+1;j<=n;++j){
if(b[id[l]]>b[id[j]])_+=a[id[j]]*l;
if(b[id[l+1]]>b[id[j]])_+=a[id[j]]<<1;
}if(_<cnt){cnt=_;memcpy(ans,b,sizeof b);}
else continue;l=1;break;
}
}cout<<cnt<<'\n';for(int j=1;j<=n;++j)cout<<ans[j]+1<<' ';
}signed main(){open;int t=1;//cin>>t;
while(t--)solve();}
为过审,删除了部分用不到的宏定义,不保证没有不小心多删