[Wannafly26B] 冥土追魂 [貪心]
阿新 • • 發佈:2018-12-15
賽時程式碼(WA)
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
#define ll long long
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12]={},*frS=frBB,*frT=frBB;
inline ll read()
{
ll x=0;char ch=0;bool w=0;
while(!isdigit(ch))w|=(ch=='-'),ch=getchar();
while(isdigit(ch))x=x*10+(ch-'0'),ch=getchar();
return w?-x:x;
}
int N,M,K;
ll Ans=0;
ll vis[1005]={};
pair<pair<ll,ll>,int> AAn[1005]={};
pair< int,int> id[1005]={};
ll Aij[1005][1005]={};
bool cmp(ll a,ll b)
{
return a>b;
}
pair<ll,ll> Lst[1005][1005]={};
int main()
{
N=(int)read(),M=(int)read(),K=(int)read();
for(int i=1;i<=N;++i)
{
for(int j=1;j<=M;++j)
{
Aij[i][j]=read();
}
sort (Aij[i]+1,Aij[i]+1+M,cmp);
for(int j=1;j<=min(M,K);++j)Lst[j][i].first=Lst[j-1][i].first+Aij[i][j],Lst[j][i].second=i;
if(K>=M)AAn[i].first.first=Lst[M][i].first;
AAn[i].first.second=Lst[K%M][i].first;
AAn[i].second=i;
}
// for(int i=1;i<=N;++i){
// for(int j=1;j<=min(M,K);++j)printf("%d ",Lst[j][i].first);
// printf("\n");
// }
sort(AAn+1,AAn+1+N);
for(int i=1;i<=min(M,K);++i)sort(Lst[i]+1,Lst[i]+1+N);
while(K)
{
if(K>=M)
{
int i=1;
while(vis[AAn[i].second])++i;
Ans+=AAn[i].first.first;
vis[AAn[i].second]=1;
}
else
{
int i=1;
while(vis[Lst[K][i].second])++i;
Ans+=Lst[K][i].first;
vis[Lst[K][i].second]=1;
}
// cout<<K<<" "<<Ans<<endl;
K-=min(K,M);
}
printf("%lld",Ans);
return 0;
}
為我的智商幹一個涼涼杯(? Alice想要讓Bob拿到最小的,Bob想要拿到最大的 那麼Alice每次會取一個“最大值最小”的行,Bob當然會取裡面的最大值… 這是十分貪心的情況,因為可能會這樣: 2 4 5 2 3 3 3 3 1 5 1 5 1 那就不行了。 如果只看行最大值的話,後面那些就顧及不到,也就有可能出現區域性最優的情況。 進一步考慮。 為什麼要放棄最大值最小的行? 考慮到從某一行裡面取的值一定是單調遞減的,可以把每一行排序。 放棄了行x,選擇了行y≠x。 有,而且在某一個位置有 當然在這一個位置行的應該是沒被選的那些行裡面最小的。 那麼這是哪一個位置? 如果可以取但是不取完,那麼就是說其它行前面的部分比y行的最後那一部分要小。 取z行作其它行的代表。 我們把這兩行按照取到的位置這麼分: (z行)ab (y行)cd (abcd各代表一部分值的和) 已經知道a>c,a>b,c>d 不取d那麼a<d 然而a>c>d。Q.E.D 所以一定會取完K/M行。至於怎麼取很簡單,按照sum從小到大排個序。 可是K%M可能≠0。 剩下的K%M行呢?從剩下沒被取的裡面拿嗎? 這個地方我打比賽的時候沒想好,就真這麼以為了(貪心貪傻了 假設選了行v的前K%M個 如果行v被選的話,那行v這一行就不能全取,要在後面另外全取一行u。 同樣假設 (v行)op (u行)qr 有p<o,o<q,q>r,q+r<o+p o+q+r<o+p+q是否可能成立? 沒有辦法知道是否r<p。所以可能成立。 至於u是哪一行那很簡單,當然是sum排序之後的第K/M+1行了。 (wannafly自閉賽
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
#define ll long long
int N,M,K;
ll Ans=0;
pair<ll,ll> AAn[1005]={};
ll Aij[1005]={};
bool cmp(ll a,ll b){return a>b;}
ll Lst[1005]={};
int main()
{
scanf("%d%d%d",&N,&M,&K);
for(int i=1;i<=N;++i)
{
for(int j=1;j<=M;++j)scanf("%lld",&Aij[j]);
sort(Aij+1,Aij+1+M,cmp);
for(int j=1;j<=M;++j)Lst[j]=Lst[j-1]+Aij[j];
AAn[i].first=Lst[min(K,M)];
AAn[i].second=Lst[K%M];
}
sort(AAn+1,AAn+1+N); int cnt=K/M;
if(!cnt){ printf("%lld",AAn[1].first); return 0;}
for(int i=1;i<=cnt;++i)Ans+=AAn[i].first;
ll tmp=Ans;
if(K%M)
{
Ans=2147483647147483647ll;
for(int i=cnt+1;i<=N;++i)
Ans=min(Ans,tmp+AAn[i].second);
for(int i=1;i<=cnt;++i)
Ans=min(Ans,tmp-AAn[i].first+AAn[i].second+AAn[cnt+1].first);
}
printf("%lld",Ans);
return 0;
}