【TEST】美团 CodeM 初赛 Round 1 || 2

3 篇文章 0 订阅
3 篇文章 0 订阅

写在最前面

这是今天的考试,一场比较水的考试,但是也不知为什么,就是爆炸了……

orz sillyf大佬,随随便便切掉了t3,然后就轻描淡写的说:“t3不就是一道很水的状压DP嘛?”

QAQ……

Orz sillyf

t1:#【LOJ】6162 「美团 CodeM 初赛 Round A」身体训练 模拟

虽然这题是一道暴力就过的水题,但是为了讲的更清楚一点,定义 f[i][j] 表示第 i 个人第为j个在最后跑的人,显然这个人对于其他人的相对速度为 c[i](j1)d[i]v f[i][j] 表示第 i 个人第为j个在最后跑的概率显然为 1/n ,跑的距离为 nu 。那么显然 f[i][j]=u/(c[i](j1)d[i]v) 。答案即为 i=1ni=1nf[i][j] ,直接 n2 求答案即可。

附上AC代码:

#include <cstdio>
using namespace std;

const int N=1e3+10;
int n;
double v,u,c[N],d[N],ans;

int main(void){
    scanf("%d%lf%lf",&n,&v,&u);
    for (int i=1; i<=n; ++i) scanf("%lf",&c[i]);
    for (int i=1; i<=n; ++i) scanf("%lf",&d[i]);
    for (int i=1; i<=n; ++i)
        for (int j=1; j<=n; ++j)
            ans+=u/(c[i]-(j-1)*d[i]-v);
    return printf("%.3lf\n",ans),0;
}

t2:#6178. 「美团 CodeM 初赛 Round B」景区路线规划 期望DP || 记忆化搜索

考试时的我就宛如一个智障,大概意思就是以为 n1nn 。考试真的是一种奇怪的东西,可以使人智熄……

发现这题就是一道非常裸的期望DP题,可惜并不会处理期望DP,只会记忆化搜索。

为了方便,我们可以建立一个虚点,和所有点建一条权值为零的边,然后直接搜索这个虚点就行了。

附上AC代码:

#include <cstdio>
using namespace std;

const int N=110;
struct side{
    int from,to,w,nt;
}s[N*N];
int n,m,t,c[N],v[3][N],x,y,w,h[N],num;
double dp[N][500][3];

inline void add(int x,int y,int w){
    s[++num]=(side){x,y,w,h[x]},h[x]=num;
    if (x) s[++num]=(side){y,x,w,h[y]},h[y]=num;
}

inline double so(int now,int ti,int o){
    if (dp[now][ti][o]) return dp[now][ti][o];
    double ret=v[o][now];int cnt=0;
    for (int i=h[now]; i; i=s[i].nt) if (ti>=s[i].w+c[s[i].to]) ++cnt;
    for (int i=h[now]; i; i=s[i].nt) if (ti>=s[i].w+c[s[i].to]) ret+=so(s[i].to,ti-s[i].w-c[s[i].to],o)/cnt;
    return dp[now][ti][o]=ret;
}

int main(void){
    scanf("%d%d%d",&n,&m,&t);
    for (int i=1; i<=n; ++i) scanf("%d%d%d",&c[i],&v[1][i],&v[2][i]),add(0,i,0);
    for (int i=1; i<=m; ++i) scanf("%d%d%d",&x,&y,&w),add(x,y,w);
    return printf("%.5lf %.5lf\n",so(0,t,1),so(0,t,2)),0;
}

t3:#6177. 「美团 CodeM 初赛 Round B」送外卖2 状压DP

首先我们可以用floyd预处理出所有节点之间的最短路。

然后我们定义 f[i][j] 表示现在在第 i <script type="math/tex" id="MathJax-Element-15">i</script>号节点,状态为j的最小时间。

j表示一个q位的三进制数,每一位表示一个外卖的状态,0表示该外卖还没有被取走,1表示该外卖已经被取走但还没有被送达,2表示该外卖已经被送达。

考虑状态之间的转移,0的时候就从当前节点到当前外卖的起点,1的时候就从当前节点到外卖的终点,注意时间边界的判断。

然后就在所有合法状态中找出送达外卖数的最大值即可。

附上AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int n,m,q,map[21][21],x,y,w,f[21][59050],pow[11],s[11],t[11],l[11],r[11];

int main(void){
    scanf("%d%d%d",&n,&m,&q),memset(map,0x3f,sizeof map);
    for (int i=1; i<=m; ++i) scanf("%d%d%d",&x,&y,&w),map[x][y]=min(map[x][y],w);
    for (int i=1; i<=n; ++i) map[i][i]=0;
    for (int k=1; k<=n; ++k)
        for (int i=1; i<=n; ++i)
            for (int j=1; j<=n; ++j)
                map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
    for (int i=1; i<=q; ++i) scanf("%d%d%d%d",&s[i],&t[i],&l[i],&r[i]);
    f[1][0]=0,pow[0]=1;
    for (int i=1; i<=10; ++i) pow[i]=pow[i-1]*3;
    for (int i=1; i<=n; ++i) for (int j=0; j<pow[q]; ++j) f[i][j]=1e9;
    for (int i=1; i<=n; ++i) f[i][0]=map[1][i];
    for (int i=0; i<pow[q]; ++i){
        for (int j=1; j<=n; ++j)
            for (int k=1; k<=q; ++k){
                int num=i%pow[k]/pow[k-1];
                if (!num)
                    if (f[j][i]+map[j][s[k]]>=l[k]) f[s[k]][i+pow[k-1]]=min(f[s[k]][i+pow[k-1]],f[j][i]+map[j][s[k]]);
                    else f[s[k]][i+pow[k-1]]=min(f[s[k]][i+pow[k-1]],l[k]);
                if (num==1) if (f[j][i]+map[j][t[k]]<=r[k]) f[t[k]][i+pow[k-1]]=min(f[t[k]][i+pow[k-1]],f[j][i]+map[j][t[k]]);
            }
    }
    int ans=0;
    for (int i=0; i<pow[q]; ++i)
        for (int j=1; j<=n; ++j)
            if (f[j][i]!=1e9){
                int t=0;
                for (int k=1; k<=q; ++k) if (i%pow[k]/pow[k-1]==2) ++t;
                ans=max(ans,t);
            }
    printf("%d\n",ans);
    return 0;
}

写在最后

以后考试的时候一定要保持状态的良好,还有要合理分配时间,不要再次出现半个小时写t3的悲剧局面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值