T1:[USACO18FEB]Rest Stops - luogu4266.
题目大意:给定一条长度为为
L
L
L直线与
n
n
n个点,每个点有坐标
x
i
x_i
xi,美味值
c
i
c_i
ci.现在给定两个人F和B从开头出发,F与B的速度分别为f,b秒每米,问B在不落后于F后能得到最大的美味值之和,其中在第
i
i
i个点停留
t
t
t秒可以得到的美味值为
t
∗
c
i
t*c_i
t∗ci.
1
≤
L
,
c
i
,
f
,
b
≤
1
0
6
,
1
<
x
i
<
L
,
1
≤
n
≤
1
0
5
1\leq L,c_i,f,b\leq 10^6,1<x_i<L,1\leq n\leq 10^5
1≤L,ci,f,b≤106,1<xi<L,1≤n≤105.
看到的第一眼想了DP,设
f
[
i
]
f[i]
f[i]表示到第
i
i
i个点并在第
i
i
i个点吃草的最大美味值,那么可以得到转移方程:
f
[
i
]
=
max
j
=
0
i
−
1
{
f
[
j
]
+
(
f
−
b
)
c
i
(
x
i
−
x
j
)
}
=
x
i
(
f
−
b
)
c
i
+
max
j
=
0
i
−
1
{
f
[
j
]
−
x
j
(
f
−
b
)
c
i
}
f[i]=\max_{j=0}^{i-1}\{f[j]+(f-b)c_i(x_i-x_j)\}=x_i(f-b)c_i+\max_{j=0}^{i-1}\{f[j]-x_j(f-b)c_i\}
f[i]=j=0maxi−1{f[j]+(f−b)ci(xi−xj)}=xi(f−b)ci+j=0maxi−1{f[j]−xj(f−b)ci}
仔细一想可以斜率优化,发现自己不会,又想到这个等级的题目怎么会是斜率优化,于是果断重新思考.
发现要吃草的话肯定吃越美味的越好,于是想到给整个序列排序,然后尽量能吃美味值大的就吃美味值大的.
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),其中瓶颈在于排序.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
struct node{
int x;
LL c;
}a[N+9];
int l,n,now;
LL ans;
bool cmp(const node &a,const node &b){return a.c>b.c;}
Abigail into(){
int x,y;
scanf("%d%d%d%d",&l,&n,&x,&y);
y=abs(y-x);
for (int i=1;i<=n;++i){
scanf("%d%lld",&a[i].x,&a[i].c);
a[i].c*=y;
}
}
Abigail work(){
sort(a+1,a+1+n,cmp);
now=0;ans=0;
for (int i=1;i<=n;++i)
if (now<=a[i].x){
ans+=LL(a[i].x-now)*a[i].c;
now=a[i].x;
}
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
//freopen("reststops.in","r",stdin);
//freopen("reststops.out","w",stdout);
into();
work();
outo();
return 0;
}
T2:[USACO18FEB]Snow Boots S - luogu4265.
题目大意:给定
n
n
n块地砖
b
b
b双鞋,第
i
i
i双鞋可以承受
s
i
s_i
si的厚度并以此走至多
d
i
d_i
di的距离》问最少只要用前几双鞋就可以从
1
1
1走到
n
n
n,注意鞋必须按顺序串,并且穿过后不能再穿.
1
≤
n
,
b
≤
250
1\leq n,b\leq 250
1≤n,b≤250.
考场调用了负数下标真是难受啊…
很容易想到一个比较大力的DP,设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示到第
i
i
i块地砖正在穿第
j
j
j双鞋是否可行,那么容易得到方程:
f
[
i
]
[
j
]
=
f
[
k
]
[
j
]
∣
∣
f
[
i
]
[
l
]
  
(
k
+
d
j
≥
i
,
1
≤
l
<
j
)
f[i][j]=f[k][j]||f[i][l]\,\,(k+d_j\geq i,1\leq l<j)
f[i][j]=f[k][j]∣∣f[i][l](k+dj≥i,1≤l<j)
时间复杂度 O ( n 3 ) O(n^3) O(n3),代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=250;
int n,m,f[N+9],s[N+9],d[N+9],ans,dp[N+9][N+9];
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",&f[i]);
for (int i=1;i<=m;++i)
scanf("%d%d",&s[i],&d[i]);
}
Abigail work(){
for (int i=1;i<=n;++i)
for (int j=0;j<=m;++j){
if (i==1&&j==0) dp[i][j]=1;
if (s[j]<f[i]) continue;
for (int k=0;k<j;++k)
dp[i][j]|=dp[i][k];
for (int k=max(i-d[j],0);k<i;++k)
dp[i][j]|=dp[k][j];
}
while (!dp[n][ans]) ++ans;
}
Abigail outo(){
printf("%d\n",ans-1);
}
int main(){
//freopen("snowboots.in","r",stdin);
//freopen("snowboots.out","w",stdout);
into();
work();
outo();
return 0;
}
T3:[USACO18FEB]Teleportation S - luogu4264.
题目大意:给定
n
n
n组
a
i
,
b
i
a_i,b_i
ai,bi,要求一个
x
x
x使得
∑
i
=
1
n
min
(
∣
a
i
−
b
i
∣
,
∣
a
i
∣
+
∣
b
i
−
x
∣
)
\sum_{i=1}^{n}\min(|a_i-b_i|,|a_i|+|b_i-x|)
∑i=1nmin(∣ai−bi∣,∣ai∣+∣bi−x∣)最小.
−
1
0
8
≤
a
i
,
b
i
≤
1
0
8
,
1
≤
n
≤
1
0
5
-10^8\leq a_i,b_i\leq 10^8,1\leq n\leq 10^5
−108≤ai,bi≤108,1≤n≤105.
考虑对于每一组
a
i
,
b
i
a_i,b_i
ai,bi都对应一个函数
y
=
min
(
∣
a
i
−
b
i
∣
,
∣
a
i
∣
+
∣
b
i
−
x
∣
)
y=\min(|a_i-b_i|,|a_i|+|b_i-x|)
y=min(∣ai−bi∣,∣ai∣+∣bi−x∣),很容易发现这个函数会是这样的:
考虑对于每一个函数求出它的三个转折点
l
i
,
m
i
,
r
i
l_i,m_i,r_i
li,mi,ri,其中用
x
i
x_i
xi代替
l
i
l_i
li和
r
i
r_i
ri,很容易发现:
∣
b
i
−
m
i
∣
=
0
,
m
i
=
b
i
∣
a
i
−
b
i
∣
=
∣
a
i
∣
+
∣
b
i
−
x
i
∣
∣
a
i
−
b
i
∣
−
∣
a
i
∣
=
∣
b
i
−
x
i
∣
|b_i-m_i|=0,m_i=b_i\\ |a_i-b_i|=|a_i|+|b_i-x_i|\\ |a_i-b_i|-|a_i|=|b_i-x_i|\\
∣bi−mi∣=0,mi=bi∣ai−bi∣=∣ai∣+∣bi−xi∣∣ai−bi∣−∣ai∣=∣bi−xi∣
令
c
i
=
∣
a
i
−
b
i
∣
−
∣
a
i
∣
c_i=|a_i-b_i|-|a_i|
ci=∣ai−bi∣−∣ai∣,分情况讨论:
1.
b
i
≥
x
i
b_i\geq x_i
bi≥xi,那么
c
i
=
b
i
−
x
i
c_i=b_i-x_i
ci=bi−xi,即
l
i
=
b
i
−
c
i
l_i=b_i-c_i
li=bi−ci.
2.
b
i
<
x
i
b_i< x_i
bi<xi,那么
c
i
=
x
i
−
b
i
c_i=x_i-b_i
ci=xi−bi,即
r
i
=
b
i
+
c
i
r_i=b_i+c_i
ri=bi+ci.
那么我们就可以轻松求出三个转折点了.
继续考虑这有什么用,我们发现一个点有可能成为最优的 x x x仅当它是任意一个函数的转折点或者这些函数均为出现转折,并且很容易发现转折后的斜率必定为 ± 1 \pm 1 ±1或 0 0 0,所以我们暴力把所以转折点放入一个map里并记录当前的斜率之和,就可以 O ( n log n ) O(n\log n) O(nlogn)解决这道题了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
#define mapit map<LL,LL>::iterator
const int N=100000;
int n;
map<LL,LL>s;
LL sum,ans;
Abigail into(){
scanf("%d",&n);
LL a,b,c;
for (int i=1;i<=n;++i){
scanf("%lld%lld",&a,&b);
c=abs(a-b);sum+=c;c-=abs(a);
if (c<0) continue;
s[b]+=2;
--s[b+c];--s[b-c];
}
}
Abigail work(){
ans=sum;
LL lx=s.begin()->first;
int x,now=0;
for (mapit it=s.begin();it!=s.end();++it){
x=it->first;
sum+=now*(x-lx);lx=x;now+=it->second;
ans=min(ans,sum);
}
}
Abigail outo(){
printf("%lld\n",ans);
}
int main(){
//freopen("teleport.in","r",stdin);
//freopen("teleport.out","w",stdout);
into();
work();
outo();
return 0;
}
T4:[USACO18FEB]Directory Traversal - luogu4268.
题目:Bessie在牛棚的电脑里用
n
n
n个文件夹储存了她所有珍贵的文件,比如:
bessie/
folder1/
file1
folder2/
file2
folder3/
file3
file4
只有一个“顶层”的文件夹,叫做bessie.
Bessie可以浏览任何一个她想要访问的文件夹.从一个给定的文件夹,每一个文件都可以通过一个“相对路径”被引用.在一个相对路径中,符号“…”指的是上级目录.如果Bessie在folder2中,她可以按下列路径引用这四个文件:
../file1
file2
../../folder3/file3
../../file4
Bessie想要选择一个文件夹,使得从该文件夹出发,对所有文件的相对路径的长度之和最小.
1
≤
n
≤
1
0
5
1\leq n\leq 10^5
1≤n≤105,所有字符串长度
≤
16
\leq 16
≤16.
考场把邻接表的数组开小了真是难受…
感觉比较套路,可以直接计算出以 1 1 1为给定文件夹时的长度和 f [ 1 ] f[1] f[1],然后通过这个来转移其它所有 f [ i ] f[i] f[i],这个用换根DP就可以实现了,时间复杂度为 O ( n ) O(n) O(n).
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
const LL INF=(1LL<<60)-1;
struct side{
int y,next;
}e[N*2+9];
int lin[N+9],top;
void ins(int x,int y){
e[++top].y=y;
e[top].next=lin[x];
lin[x]=top;
}
int siz[N+9],n,leaf[N+9],b[N+9];
LL ans[N+9],mn=INF;
char c[N+9];
void dfs1(int k,int fa){
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^fa){
dfs1(e[i].y,k);
leaf[k]+=leaf[e[i].y];
}
if (k^1) ans[1]+=(LL)leaf[k]*siz[k];
}
void dfs2(int k,int fa){
ans[k]=ans[fa]+3LL*(leaf[1]-leaf[k])-(LL)leaf[k]*siz[k];
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^fa) dfs2(e[i].y,k);
}
Abigail into(){
scanf("%d",&n);
int m,y;
for (int i=1;i<=n;++i){
scanf("%s%d",c+1,&m);
siz[i]=strlen(c+1);
if (m==0) leaf[i]=b[i]=1;
else{
++siz[i];
for (int j=1;j<=m;++j){
scanf("%d",&y);
ins(i,y);ins(y,i);
}
}
}
}
Abigail work(){
dfs1(1,0);
for (int i=lin[1];i;i=e[i].next)
dfs2(e[i].y,1);
for (int i=1;i<=n;++i)
if (!b[i]) mn=min(mn,ans[i]);
}
Abigail outo(){
printf("%lld\n",mn);
}
int main(){
//freopen("dirtraverse.in","r",stdin);
//freopen("dirtraverse.out","w",stdout);
into();
work();
outo();
return 0;
}