序
作为一只菜鸡,本场比赛的题一下子把我搞懵逼了,在队友过了H之后,剩余的时间无所事事,于是就开始各种瞎搞F题,最后还真的用一种制杖操作给过了,在此放出这种方法,主要是因为我也不知道为什么能过,希望和各位大佬一起探讨一下,如果有大佬能给出样例就更好了,欢迎大家指正,求各位轻虐,鄙人在此谢过了233.
主体思路
这种方法制杖的地方就在于,我是贪心写的orz(可把我牛逼坏了,叉会儿腰,等等......腰呢!?)。我最初的想法是,可以看成一开始就有2*n个人在一组,竞争值是0,这时你要依次取出n个人来,使最终的竞争值最大,然后我就想到了每一步贪心的方法......(是不是很奇葩?)
最初的想法是这样的,在一开始先将矩阵的每一行的和求出来,这个值的含义是:第i行的和表示你取走第i个人之后增加的竞争值,每次选取最大的那个人,每当取走一个人,就把他所在的行和列删除,然后重复以上过程,n次后就可以得到一个值,但这个答案显然是错误的。
因为每次取下一个人的时候,都会影响之前所得到的竞争值,举个例子说,若是先取走了1号,当前竞争值是,假如接下来取走2号,那么原先的竞争值就会损失一部分,即,然后还会得到,所有从第2步开始,一直到第n步,需要考虑当前行的和减去已选取的人的影响/的最大值,但是考虑了这一点之后依然没有过,赛后看结果只过了36%。
除此之外,还有一个是贪心的起始点的问题,因为当选取第一个人的时候,另一边没有影响,在缺乏这一约束的情况下,起始点的选取应该如何抉择?所以我干脆试了次,然而依然没有过,赛后看结果,这份代码过了68%。
至此,在赛中我已经放弃了这个方法,后来是学姐帮忙搜过的。(事实上学姐一开始就说搜索,还有枚举也可以,没想到赛后看代码真的有大佬400行枚举)
赛后我又重新构思,发现好像这个方法只是不断贴近正确结果,例如第一步的选取,我依次尝试,就可以一定程度提高正确率,那么我第二步的选取也遍历一遍呢?按照这个数据量应该是可以把前四步的选取情况都暴力出来的,那么应该差不多过了。
然后,我只考虑了前两步,后面直接贪,就过了......过了......了......
代码
//加了注释就成了14ms,我也不知道为什么 #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; ll a[30][30];//存竞争值的数组 bool bo[30];//好像是定义了没用上的东西 ll jl[30];//同上 struct node{ ll z;//当前状态下对剩余人的竞争值之和 ll f;//标记序号 ll si;//已选取的人的影响值 ll bj;//标记贡献值,bj=z-si }b[30];//存每个人的信息 bool cmp(node x,node y){ return x.bj<y.bj; } int main(){ ll n; node t1; scanf("%lld",&n); for(ll i=1;i<=n*2;i++){ for(ll j=1;j<=n*2;j++){ scanf("%lld",&a[i][j]); } } ll ans=0,ans1=0; for(int k=1;k<=n*2;k++)//初始点选取 { for(int q=1;q<=n*2;q++){//第二个点 ans=0; //每次重新初始化b,制杖操作,不要理会 for(int hh=1;hh<=n*2;hh++){ b[hh].z=0; } for(ll i=1;i<=n*2;i++){ for(ll j=1;j<=n*2;j++){ b[i].z+=a[i][j]; b[i].f=i; b[i].si=0; } } if(k==q) continue; //把要选取的两个点放最后 t1=b[k]; b[k]=b[n*2]; b[n*2]=t1; t1=b[q]; b[q]=b[n*2-1]; b[n*2-1]=t1; //第一步的处理 ans+=b[n*2].z-b[n*2].si; for(ll j=1;j<=n*2-1;j++){ b[j].z-=a[b[j].f][b[n*2].f]; b[j].si+=a[b[j].f][b[n*2].f]; b[j].bj=b[j].z-b[j].si; } //剩下每一步的处理,每次对贡献值排序 for(ll i=2;i<=n;i++){ ans+=b[n*2+1-i].z-b[n*2+1-i].si; for(ll j=1;j<=n*2-i;j++){ b[j].z-=a[b[j].f][b[n*2+1-i].f]; b[j].si+=a[b[j].f][b[n*2+1-i].f]; b[j].bj=b[j].z-b[j].si; } sort(b+1,b+n*2+1-i,cmp); } //更新答案最大值 ans1=max(ans1,ans); } } printf("%lld\n",ans1); } /*3 0 3 5 4 1 2 3 0 7 8 9 1 5 7 0 11 2 3 4 8 11 0 5 6 1 9 2 5 0 7 2 1 3 6 7 0*/