game
一个n*m的矩阵,总共删掉k个数,每次选择一行删掉里面最大的数字,求删掉数字总和的最小值.
非常快地想到一个贪心:每次删掉最大数最小的行的最大数.
被轻松hack.
2 3 4
4 4 4
5 1 1
再往深了想:每次删掉某一行的最大数之后,必须删掉这一行的所有数,不然显然不值.
那么找到所有数之和最小的几行,如果和相同按照最大的几个值从小到大排.
最后把去掉很多行剩下的数字
r
e
m
rem
rem每行按照
r
e
m
rem
rem个数的和排序,排序方法和上面一样.
这样就可以…轻松获得
30
30
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);
}
为什么呢?
对于某一行来说,这行既有可能全部取,也有可能只取
r
e
m
rem
rem个.
那么我们枚举所有行,在这行取
r
e
m
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. d i s ( a , b ) = p 2. d i s ( c , d ) = q 3. ( a , b ) 和 ( c , d ) 两 条 路 径 没 有 交 点 . n ≤ 3000. 给一棵树,求符合以下条件的四元组(a,b,c,d)的总数.\newline 1.dis(a,b)=p \newline 2.dis(c,d)=q\newline 3.(a,b)和(c,d)两条路径没有交点.\newline n\leq 3000. 给一棵树,求符合以下条件的四元组(a,b,c,d)的总数.1.dis(a,b)=p2.dis(c,d)=q3.(a,b)和(c,d)两条路径没有交点.n≤3000.
枚举 a , b a,b a,b,满足条件的 c , d c,d c,d满足下列两种情况的一种.
- l c a ( c , d ) lca(c,d) lca(c,d)在 l c a ( a , b ) lca(a,b) lca(a,b)的子树内.
- l c a ( c , d ) lca(c,d) lca(c,d)不在 l c a ( a , b ) lca(a,b) lca(a,b)的子树内.
那么对于第一种情况,
l
c
a
(
c
,
d
)
lca(c,d)
lca(c,d)不在
a
→
b
a\to b
a→b的路径上就可以了.
预处理
f
[
i
]
f[i]
f[i]为经过
i
i
i长度为
q
q
q的路径数.
对于第二种情况,
c
→
d
c\to d
c→d的路径不经过连接
l
c
a
(
a
,
b
)
lca(a,b)
lca(a,b)和
f
a
[
l
c
a
(
a
,
b
)
]
fa[lca(a,b)]
fa[lca(a,b)]的边就可以了.
预处理经过每一条边,长度为
q
q
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
=
1
n
i
m
o
d
p
i
=
s
构造一个排列使得\sum_{i=1}^{n}i\ mod\ p_{i}=s
构造一个排列使得∑i=1ni mod pi=s.
首先我们发现
s
s
s的最大值是
n
×
(
n
−
1
)
2
.
\frac{n\times(n-1)}{2}.
2n×(n−1).
接下来我们通过构造证明
0
→
n
×
(
n
−
1
)
2
0\to \frac{n\times(n-1)}{2}
0→2n×(n−1)的值都可以取到.
首先令
p
[
n
]
=
1
,
p
[
1
]
=
2
,
p
[
i
]
=
i
(
i
∈
{
2
,
3
,
4
,
.
.
.
,
n
−
1
}
)
,
i
∉
g
p[n]=1,p[1]=2,p[i]=i (i\in \{2,3,4,...,n-1\}),i\notin g
p[n]=1,p[1]=2,p[i]=i(i∈{2,3,4,...,n−1}),i∈/g,其中
g
⊆
{
2
,
3
,
4
,
.
.
.
,
n
−
1
}
g\subseteq \{2,3,4,...,n-1\}
g⊆{2,3,4,...,n−1},然后从小到大枚举
i
∈
g
i\in g
i∈g,将
p
[
i
]
p[i]
p[i]赋值为最小没有选择过的数.这样对于
i
∈
g
i\in g
i∈g来说,
p
[
i
]
>
i
p[i]>i
p[i]>i,故此法可行.
那么只剩下构造
s
∈
{
0
,
2
,
n
×
(
n
−
1
)
2
−
1
}
s\in\{0,2,\frac{n\times(n-1)}{2}-1\}
s∈{0,2,2n×(n−1)−1}的情况.
1.
当
s
=
0
时
,
p
[
i
]
=
i
.
2.
当
s
=
2
时
,
p
[
1
]
=
3
,
p
[
2
]
=
1
,
p
[
3
]
=
2
,
剩
下
p
[
i
]
=
i
.
3.
当
s
=
n
×
(
n
−
1
)
2
−
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.
1.当s=0时,p[i]=i.\newline 2.当s=2时,p[1]=3,p[2]=1,p[3]=2,剩下p[i]=i.\newline 3.当s=\frac{n\times(n-1)}{2}-1时: \newline 若n是奇数,p[1]=3,p[2]=1,p[n]=2,剩下p[i]=i+1. \newline 若n是偶数,p[1]=1,p[n]=2,剩下p[i]=i+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×(n−1)−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]);
}
谢谢大家.