T 1 T_1 T1——river(3035)
Description:
有一个座长度为
L
L
L的范围为
[
1
,
L
]
[1,L]
[1,L]的桥,而桥上有
m
m
m个石子,从起点
1
1
1开始,跳,每次跳的范围为
[
S
,
T
]
[S,T]
[S,T],求最少踩几个石子过桥。
L
≤
1
0
9
,
m
≤
100
,
s
≤
t
≤
300
L\le10^9,m\le100,s\le t\le300
L≤109,m≤100,s≤t≤300
Solution:
- 此题的关键就在于石子很少且步长很短,而桥很长。
- 换句话说,有很多点是无用的,
- 那么我们就需要把这些石子之间的无用点离散掉。
- 不难发现,我们只关心每个石子之前的 T T T个单位和之后的 S S S个单位。
- 再根据暴力的 Θ ( L ( T − S ) ) \Theta(L(T-S)) Θ(L(T−S))的 d p dp dp模拟即可。
- 另外,对于70%的做法,显然可以用单调栈 Θ ( L ) \Theta(L) Θ(L)解决。
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
const int N=102,M=1e7+2;
int n,s,t,Len;
int pos[N];
bool mp[M];
struct p30{
int dp[10500];
void solve(){
REP(i,1,n) mp[pos[i]]=1;
memset(dp,63,sizeof(dp));
dp[0]=0;
REP(i,0,Len) REP(j,s,t) chkmin(dp[i+j],dp[i]+mp[i+j]);
int ans=0x3f3f3f3f;
REP(i,Len,Len+t) chkmin(ans,dp[i]);
printf("%d\n",ans);
}
}p1;
struct p70{
int Q[M],L,R;
int dp[M];
void solve(){
REP(i,1,n) mp[pos[i]]=1;
L=1,R=0;
int ans=0x3f3f3f3f;
memset(dp,63,sizeof(dp));
dp[0]=0;
REP(i,s,Len){
while(L<=R&&Q[L]+t<i)++L;
while(L<=R&&dp[i-s]<=dp[Q[L]])++L;
Q[++R]=i-s;
dp[i]=dp[Q[L]]+mp[i];
if(i+t>Len)chkmin(ans,dp[i]);
}
printf("%d\n",ans);
}
}p2;
struct p100{
int dp[M];
int dis[N];
void solve(){
sort(pos+1,pos+1+n);
memset(dp,63,sizeof(dp));
dp[0]=0;
REP(i,1,n) dis[i]=pos[i]-pos[i-1];
REP(i,1,n){
if(dis[i]>=300) pos[i]=pos[i-1]+300+(dis[i]-300)%t;
else pos[i]=pos[i-1]+dis[i];
mp[pos[i]]=1;
}
Len=pos[n];
REP(i,s,Len+t) REP(j,max(0,i-t),i-s) chkmin(dp[i],dp[j]+mp[i]);
int ans=0x3f3f3f3f;
REP(i,Len,Len+t) chkmin(ans,dp[i]);
printf("%d\n",ans);
}
}p3;
int main(){
// freopen("river.in","r",stdin);
// freopen("river.out","w",stdout);
scanf("%d%d%d%d",&Len,&s,&t,&n);
REP(i,1,n) scanf("%d",&pos[i]);
if(Len<=1e4)p1.solve();
else if(Len<=1e7)p2.solve();
else p3.solve();
return 0;
}
T 2 T_2 T2——barn(3038)
Description:
有
n
n
n个谷仓排列成一个环,编号为1~n,每个谷仓都住了不同数量的牛,第
i
i
i个谷仓住了
r
i
r_i
ri头牛,现在开
k
k
k个谷仓的入口,让牛从这个
k
k
k个谷仓进入,然后按照顺时针到各自该去的地方,求牛走的路程和的最小值。
n
≤
500
,
k
≤
10
,
r
i
≤
1
0
6
n\le 500,k\le10,r_i\le10^6
n≤500,k≤10,ri≤106
Solution:
- das
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
const int N=502,M=12;
int n,m;
ll A[N];
ll sum[N],Sum[N];
int Q[N],L,R;
ll dp[M][N];
ll Get_X(int x,int y){
return x-y;
}
ll Get_Y(int x,int y,int r){
return (dp[r][x]-Sum[x]+sum[x]*x)-(dp[r][y]-Sum[y]+sum[y]*y);
}
int main(){
// freopen("barn.in","r",stdin);
// freopen("barn.out","w",stdout);
scanf("%d%d",&n,&m);
REP(i,1,n) scanf("%lld",&A[i]);
ll ans=0x3f3f3f3f3f;
REP(rr,1,n){
sum[0]=Sum[0]=0;
REP(i,1,n) sum[i]=sum[i-1]+A[i],Sum[i]=Sum[i-1]+A[i]*(i-1);
memset(dp,63,sizeof(dp));
dp[0][0]=0;
REP(j,1,m){
L=1,R=0;
Q[++R]=0;
REP(i,1,n){
while(L<R && Get_Y(Q[L+1],Q[L],j-1)<=sum[i]*Get_X(Q[L+1],Q[L]))++L;
dp[j][i]=dp[j-1][Q[L]]+(Sum[i]-Sum[Q[L]])-(sum[i]-sum[Q[L]])*Q[L];
while(L<R && Get_Y(i,Q[R],j-1)*Get_X(Q[R],Q[R-1])<=Get_Y(Q[R],Q[R-1],j-1)*Get_X(i,Q[R]))--R;
Q[++R]=i;
}
}
chkmin(ans,dp[m][n]);
REP(i,1,n) A[i-1]=A[i];
A[n]=A[0];
}
printf("%lld\n",ans);
return 0;
}
T 3 T_3 T3——mosquito(3453)
Description:
有一棵
n
n
n个节点的树,在它的
m
m
m个叶子上,对于每一对叶子,有一只蚊子从叶子
a
a
a到叶子
b
b
b,而另一只从叶子
b
b
b到叶子
a
a
a。现在在根节点
1
1
1有个作用范围为
D
D
D的灭蚊器,即若
1
1
1到
x
x
x的距离不超过
D
D
D的蚊子会被打到,而对于每次打蚊子有
p
q
\frac{p}{q}
qp的概率打死。求打死蚊子个数的期望。
m
<
n
≤
1
0
6
,
D
≤
n
,
p
≤
q
≤
20000
m<n\le10^6,D\le n,p\le q\le 20000
m<n≤106,D≤n,p≤q≤20000
Solution:
Code:
#include<bits/stdc++.h>
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i<i##_end_;++i)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;--i)
#define ll long long
template<class T>inline void Rd(T &x){
x=0;char c;
while((c=getchar())<48);
do x=(x<<1)+(x<<3)+(c^48);
while((c=getchar())>47);
}
const int N=1e6+2,mod=1e9+7;
int n,D;
ll p,q,can,cant;
int head[N],qwq;
struct edge{
int to,nxt;
}E[N<<1];
void addedge(int x,int y){E[qwq]=(edge){y,head[x]};head[x]=qwq++;}
#define EREP(x) for(int i=head[x];~i;i=E[i].nxt)
int sz[N],fa[N],dep[N],son[N],top[N];
int degree[N];
int Q[N],len;
void Add(ll &x,ll y){
x+=y;
if(x>=mod)x-=mod;
}
ll Pow(ll a,ll b){
ll x=1;
while(b){
if(b&1)x=x*a%mod;
a=a*a%mod,b>>=1;
}
return x;
}
struct p50{
void dfs1(int x,int f){
fa[x]=f;
sz[x]=1;
son[x]=0;
EREP(x){
int y=E[i].to;
if(y==f)continue;
dep[y]=dep[x]+1;
dfs1(y,x);
sz[x]+=sz[y];
if(sz[son[x]]<sz[y]) son[x]=y;
}
}
void dfs2(int x,int tp){
top[x]=tp;
if(son[x])dfs2(son[x],tp);
EREP(x){
int y=E[i].to;
if(y==fa[x] || y==son[x]) continue;
dfs2(y,y);
}
}
int Lca(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int cnt[N];
void solve(){
dfs1(1,0),dfs2(1,1);
REP(i,1,len) REP(j,i+1,len) {
int x=Q[i],y=Q[j],lca=Lca(x,y);
if(dep[lca]>D)continue;
int d=min(dep[x],D)+min(dep[y],D)-2*dep[lca]+1;
cnt[d]+=2;
}
ll sum=0,ans=0;
REP(i,1,n){
Add(sum,Pow(cant,i-1)*can%mod);
if(!cnt[i])continue;
Add(ans,sum*cnt[i]%mod);
}
printf("%lld\n",ans);
}
}p1;
struct p100{
ll sum[N];
ll ans;
void dfs(int x,int f){
EREP(x){
int y=E[i].to;
if(y==f)continue;
dep[y]=dep[x]+1;
dfs(y,x);
if(dep[x]<=D){
Add(ans,1ll*sz[x]*sz[y]%mod);
if(!sum[y])sum[y]=sz[y];
Add(ans,mod-sum[x]*sum[y]%mod);
Add(sum[x],sum[y]*cant%mod);
}
sz[x]+=sz[y];
}
if(degree[x]==1){
sz[x]=1;
sum[x]=dep[x]<=D?cant:0;
}
}
void solve(){
dfs(1,0);
printf("%lld\n",ans*2%mod);
}
}p3;
int main(){
// freopen("mosquito.in","r",stdin);
// freopen("mosquito.out","w",stdout);
Rd(n);
memset(head,-1,sizeof(head));
SREP(i,1,n){
int a,b;
Rd(a),Rd(b);
addedge(a,b);
addedge(b,a);
degree[a]++,degree[b]++;
}
Rd(D),Rd(p),Rd(q);
can=p*Pow(q,mod-2)%mod;
cant=(q-p)*Pow(q,mod-2)%mod;
REP(i,1,n) if(degree[i]==1) Q[++len]=i;
if(n<=3000 || len<=500) p1.solve();
else p3.solve();
return 0;
}