文章目录

game

一个n*m的矩阵,总共删掉k个数,每次选择一行删掉里面最大的数字,求删掉数字总和的最小值.
非常快地想到一个贪心:每次删掉最大数最小的行的最大数.
被轻松hack.

2 3 4
4 4 4
5 1 1

再往深了想:每次删掉某一行的最大数之后,必须删掉这一行的所有数,不然显然不值.
那么找到所有数之和最小的几行,如果和相同按照最大的几个值从小到大排.
最后把去掉很多行剩下的数字rem每行按照rem个数的和排序,排序方法和上面一样.
这样就可以…轻松获得30分.

#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);
}

为什么呢?
对于某一行来说,这行既有可能全部取,也有可能只取rem个.
那么我们枚举所有行,在这行取rem个,剩下的行我们用上面的方法贪心即可.

#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

,(a,b,c,d).1.dis(a,b)=p2.dis(c,d)=q3.(a,b)(c,d).n3000.

枚举a,b,满足条件的c,d满足下列两种情况的一种.

  1. lca(c,d)lca(a,b)的子树内.
  2. lca(c,d)不在lca(a,b)的子树内.

那么对于第一种情况,lca(c,d)不在ab的路径上就可以了.
预处理f[i]为经过i长度为q的路径数.
对于第二种情况,cd的路径不经过连接lca(a,b)fa[lca(a,b)]的边就可以了.
预处理经过每一条边,长度为q的路径就可以了.

#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

使i=1ni mod pi=s.
首先我们发现s的最大值是2n×(n1).
接下来我们通过构造证明02n×(n1)的值都可以取到.
首先令p[n]=1,p[1]=2,p[i]=i(i{2,3,4,...,n1}),i/g,其中g{2,3,4,...,n1},然后从小到大枚举ig,将p[i]赋值为最小没有选择过的数.这样对于ig来说,p[i]>i,故此此法可行.
那么只剩下构造s{0,2,2n×(n1)1}的情况.
1.s=0,p[i]=i.2.s=2,p[1]=3,p[2]=1,p[3]=2,p[i]=i.3.s=2n×(n1)1:n,p[1]=3,p[2]=1,p[n]=2,p[i]=i+1.n,p[1]=1,p[n]=2,p[i]=i+1.
好了构造完成.

#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]);
}

谢谢大家.

10-05 19:56