game
一个n*m的矩阵,总共删掉k个数,每次选择一行删掉里面最大的数字,求删掉数字总和的最小值.
非常快地想到一个贪心:每次删掉最大数最小的行的最大数.
被轻松hack.
2 3 4
4 4 4
5 1 1
再往深了想:每次删掉某一行的最大数之后,必须删掉这一行的所有数,不然显然不值.
那么找到所有数之和最小的几行,如果和相同按照最大的几个值从小到大排.
最后把去掉很多行剩下的数字
每行按照
个数的和排序,排序方法和上面一样.
这样就可以…轻松获得
分.
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int aoi=1018;
int a[aoi][aoi],n,m,k,b[aoi][aoi];
struct nico{
int id; ll sum;
bool operator <(const nico &b) const{
if (sum^b.sum) return sum<b.sum;
for (int i=1;i<=n;++i)
if (a[id][i]^a[b.id][i])
return a[id][i]>a[b.id][i];
return id<b.id;
}
}node[aoi];
int main(){
int i,j;
n=read(),m=read(),k=read();
for (i=1;i<=n;sort(a[i]+1,a[i]+m+1,greater<int>()),++i)
for (j=1;j<=m;++j) node[i].id=i,node[i].sum+=a[i][j]=read();
sort(node+1,node+n+1);
memcpy(b,a,sizeof a);
for (i=1;i<=n;++i)
for (j=1;j<=m;++j) a[i][j]=b[node[i].id][j];
ll llx=0;
for (i=1;i<=n&&k>=m;++i) llx+=node[i].sum,k-=m;
int now=i;
for (i=now;i<=n;++i)
for (node[i]=nico{i,0ll},j=1;j<=k;++j)
node[i].sum+=a[i][j];
sort(node+now,node+n+1);
for (i=1;i<=k;++i) llx+=a[node[now].id][i];
write(llx);
}
为什么呢?
对于某一行来说,这行既有可能全部取,也有可能只取
个.
那么我们枚举所有行,在这行取
个,剩下的行我们用上面的方法贪心即可.
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int aoi=1018;
ll a[aoi][aoi],tmp[aoi];
int main(){
int i,j,n,m,k,l;
n=read(),m=read(),k=read();
for (i=1;i<=n;++i){
for (j=1;j<=m;++j) a[i][j]=read();
sort(a[i]+1,a[i]+m+1,greater<ll>());
for (j=1;j<=m;++j) a[i][j]+=a[i][j-1];
}
int net=k/m,rem=k%m;
if (!rem) rem=m,net--; // 特判rem等于0,否则当k=n*m的时候会爆炸.
ll llx=1e18,zxy;
for (i=1;i<=n;++i){
for (*tmp=zxy=0,j=1;j<=n;++j)
if (j^i) tmp[++*tmp]=a[j][m];
sort(tmp+1,tmp+*tmp+1);
for (j=1;j<=net;++j) zxy+=tmp[j];
llx=min(llx,zxy+a[i][rem]);
}
write(llx);
}
tree
枚举 ,满足条件的 满足下列两种情况的一种.
- 在 的子树内.
- 不在 的子树内.
那么对于第一种情况,
不在
的路径上就可以了.
预处理
为经过
长度为
的路径数.
对于第二种情况,
的路径不经过连接
和
的边就可以了.
预处理经过每一条边,长度为
的路径就可以了.
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int aoi=3018;
vector<int> lj[aoi];
typedef int lxy[aoi];
lxy a,b,dep,fa,pa[aoi]; // a是经过i长度为q的路径数,b是经过i与fa[i]的边,长度为q的路径数.
void dfs(int u,int f){
dep[u]=dep[fa[u]=f]+1;
for (int v:lj[u]) if (v^f) dfs(v,u);
}
int lca(int u,int v){
return u==v?u:
~pa[u][v]?pa[u][v]:
pa[u][v]=dep[u]>dep[v]?lca(fa[u],v):lca(u,fa[v]);
}//记忆化预处理lca
int dist(int u,int v){
return dep[u]+dep[v]-(dep[lca(u,v)]<<1);
}//两点间距离
void dfs(int u){
a[u]+=a[fa[u]];
for (int v:lj[u]) if (v^fa[u]) dfs(v),b[u]+=b[v];
}
int main(){
int n,p,q,i,j; n=read(),p=read(),q=read();
for (i=1;i<n;++i){
int u=read(),v=read();
lj[u].push_back(v);
lj[v].push_back(u);
}dfs(1,0);
memset(pa,-1,sizeof pa);
int cnt=0; ll llx=0;
for (i=1;i<=n;++i)
for (j=1;j<=n;++j) if (dist(i,j)==q)
++cnt,++a[lca(i,j)],++b[i],++b[j],b[lca(i,j)]-=2;
dfs(1);
for (i=1;i<=n;++i)
for (j=1;j<=n;++j) if (dist(i,j)==p)
llx+=cnt-a[i]-a[j]+a[lca(i,j)]+a[fa[lca(i,j)]]-b[lca(i,j)];
write(llx);
}
perm
.
首先我们发现
的最大值是
接下来我们通过构造证明
的值都可以取到.
首先令
,其中
,然后从小到大枚举
,将
赋值为最小没有选择过的数.这样对于
来说,
,故此此法可行.
那么只剩下构造
的情况.
好了构造完成.
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const char no_solution[]="nO 5oLuTi0N";
const int yuzu=1e5;
typedef int fuko[yuzu|10];
int main(){
ll n,s; read(n),read(s);
if (s*2>n*(n-1)) return puts(no_solution),0;
if (!s){
for (int i=1;i<=n;++i) write(i),p32;
return 0;
}
if (s==2){
printf("3 1 2 ");
for (int i=4;i<=n;++i) write(i),p32;
return 0;
}
if (s*2+2==n*(n-1)){
if (n&1){
printf("3 1 ");
for (int i=3;i<n;++i) write(i+1),p32;
puts("2");
}
else{
printf("1 ");
for (int i=2;i<n;++i) write(i+1),p32;
puts("2");
}
return 0;
}
static fuko a,b;
a[n]=b[n]=1;
for (int i=n-1;i>1;--i)
if (s-i>0&&(s-i)^2) b[i]=1,s-=i;
for (int i=2;i<n;++i) if (!b[i]) a[i]=i;
int p=2;
for (int i=1;i<=n;++i)
if (!a[i]){
for (;!b[p];++p);
a[i]=p++;
}
for (int i=1;i<=n;++i) printf("%d ",a[i]);
}
谢谢大家.