小 C 正在玩一款排兵布阵的游戏。在游戏中有 n 座城堡,每局对战由两名玩家来争夺这些城堡。每名玩家有 m 名士兵,可以向第 i 座城堡派遣 ai 名士兵去争夺这个城堡,使得总士兵数不超过 m。
如果一名玩家向第 i 座城堡派遣的士兵数严格大于对手派遣士兵数的两倍,那么这名玩家就占领了这座城堡,获得 i 分。
现在小 C 即将和其他 s 名玩家两两对战,这 s 场对决的派遣士兵方案必须相同。小 C 通过某些途径得知了其他 s 名玩家即将使用的策略,他想知道他应该使用什么策略来最大化自己的总分。
由于答案可能不唯一,你只需要输出小 C 总分的最大值。
输入格式
输入第一行包含三个正整数 s,n,m,分别表示除了小 C 以外的玩家人数、城堡数和每名玩家拥有的士兵数。
接下来 s 行,每行 n 个非负整数,表示一名玩家的策略,其中第 i 个数 ai 表示这名玩家向第 i 座城堡派遣的士兵数。
输出格式
输出一行一个非负整数,表示小 C 获得的最大得分。
输入输出样例
输入 #1复制
1 3 10 2 2 6
输出 #1复制
3
输入 #2复制
2 3 10 2 2 6 0 0 0
输出 #2复制
8
说明/提示
样例1解释:
小 C 的最佳策略为向第 11 座城堡和第 22 座城堡各派遣 55 名士兵。
样例2解释:
小 C 的最佳策略之一为向第 11 座城堡派遣 22 名士兵,向第 22 座城堡派遣 55 名士兵,向第 33 座城堡派遣 11 名士兵。
分组背包变式
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define endl '\n'
#define lowbit(x) ((x)&-(x))
const int N=2e6+10;
typedef long long ll;
ll ans=0,n1,m1;
ll t=0,s1=0,s2=0,s3=0,s4=0,max1=0,max2=0,min1=100000000,sum=0,n,m,i,j,k,r,l;
inline int read() {
bool sym=0;
int res=0;
char ch=getchar();
while(!isdigit(ch))sym |=(ch =='-'),ch=getchar();
while(isdigit(ch)) res =(res<<3)+(res<<1)+(ch^48),ch=getchar();
return sym ? -res : res;
}
void print(int x) {
if(!x)return;
print(x/10);
putchar(x%10+'0');
}
int isPrime(int n)
{
float n_sqrt;
if(n==1) return 0;
if(n==2 || n==3) return 1;
if(n%6!=1 && n%6!=5) return 0;
n_sqrt=floor(sqrt((float)n));
for(int i=5;i<=n_sqrt;i+=6)
{
if(n%(i)==0 | n%(i+2)==0) return 0;
}
return 1;
}
ll s;
ll w[1007][1008],dp[1000000];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>s>>n>>m;
for(i=1;i<=s;i++){
for(j=1;j<=n;j++){
cin>>w[j][i];//输入按每个城池一组,城池内玩家人数为s;
}
}
/*for(i=1;i<=s;i++){
for(j=1;j<=n;j++){
cout<<w[j][i]<<" ";
}
cout<<endl;
}*/
for(i=1;i<=n;i++){
sort(w[i]+1,w[i]+s+1);//按每个城池出兵人数排序
}
/*for(i=1;i<=s;i++){
for(j=1;j<=n;j++){
cout<<w[j][i]<<" ";
}
cout<<endl;
}*/
for(i=1;i<=n;i++){//分组背包
for(j=m;j>=0;j--){
for(k=1;k<=s;k++){
if(j>=w[i][k]*2+1){
dp[j]=max(dp[j],dp[j-w[i][k]*2-1]+i*k);//i*k为分数
}
}
}
}
cout<<dp[m];
return 0;
}
//mio lover