假日团队赛34 (A C(图+概率dp) )

题目链接

A-组合数问题

A题预处理一下就可以了,记得组合数给k取模

#include<bits/stdc++.h>
using namespace std;
const int N=2e3+10;
typedef  unsigned long long ll;
ll C[N][N],dp[N][N];
int k;

void init()
{
    C[0][0]=1;
    for(int i=1;i<N;++i) C[i][0]=1;

    for(int i=1;i<N;++i)
    for(int j=1;j<=i;++j){
        C[i][j]=C[i-1][j]+C[i-1][j-1];
        C[i][j]%=k;
        if(C[i][j]==0) dp[i][j]++;
    }

    //printf("%llu\n",C[2000][100]);

    for(int i=1;i<N;++i)
    for(int j=0;j<N;++j)
    dp[i][j]+=dp[i-1][j];

    for(int i=0;i<N;++i)
    for(int j=1;j<N;++j)
    dp[i][j]+=dp[i][j-1];
}
int main()
{
    int _;cin>>_>>k;
    init();
    while(_--)
    {
        int n,m;
        scanf("%d%d",&n,&m);
        m=min(m,n);
        printf("%llu\n",dp[n][m]);
    }
}

C-换教室

题目描述:
对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程。
在可以选择的课程中,有 2n 节课程安排在 n 个时间段上。在第 i (1 ≤ i ≤ n)个时间段上,两节内容相同的课程同时在不同的地点进行,其中,牛牛预先被安排在教室 ci 上课,而另一节课程在教室 di 进行。
在不提交任何申请的情况下,学生们需要按时间段的顺序依次完成所有的 n 节安排好的课程。如果学生想更换第i节课程的教室,则需要提出申请。若申请通过,学生就可以在第 i 个时间段去教室 di 上课,否则仍然在教室 ci 上课。
由于更换教室的需求太多,申请不一定能获得通过。通过计算,牛牛发现申请更换第 i 节课程的教室时,申请被通过的概率是一个已知的实数 ki,并且对于不同课程的申请,被通过的概率是互相独立的。
学校规定,所有的申请只能在学期开始前一次性提交,并且每个人只能选择至多 m 节课程进行申请。这意味着牛牛必须一次性决定是否申请更换每节课的教室,而不能根据某些课程的申请结果来决定其他课程是否申请;牛牛可以申请白己最希望更换教室的 m 门课程,也可以不用完这 m 个申请的机会,甚至可以一门课程都不申请。
因为不同的课程可能会被安排在不同的教室进行,所以牛牛需要利用课问时间从一间教室赶到另一间教室。
牛牛所在的大学有 v 个教室,有 e 条道路。每条道路连接两间教室,并且是可以双向通行的。由于道路的长度和拥堵程度不同,通过不同的道路耗费的体力可能会有所不同。当第 i(1 ≤ i ≤ n - 1)节课结束后,牛牛就会从这节课的教室出发,选择一条耗费体力最少的路径前往下一节课的教室。
现在牛牛想知道,申请哪几门课程可以使他因在教室问移动耗费的体力值的总和的期望值最小,请你帮他求出这个最小值。

题意:给你n,m,v,e  代表有n个时间段安排,v个教室,e条教室之间的边,

接下来一行n个数c[i]代表这个学期你的上课该去哪个教室的情况,

接下来一行n个数d[i]代表如果你要申请更换教室那么就从c[i]->d[i]

接下来一行n个数p[i]代第i次申请 成功的概率,

你最多进行m次申请

问如何申请使得你走的距离的期望是最小的,输出这个距离期望

做法:概率dp一下,f[i][j]代表前i门课程申请j次  且当前i课 不申请 的最小期望

g[i][j]代表前i门课程申请j次  且当前i课 申请 的最小期望

那么每次只需要考虑前一门课跟这门的是否申请情况来推出dp方程即可

状态找一个最优的推过来即可

枚举当前是否申请,接着枚举前一个是否申请

当前i课不申请:两种其中一个:c[i-1]->c[i] ,d[i-1]->c[i] 

第二钟  由于 前一个是存在申请 有概率的成功

所以就是g[i-1][j]+dis[c[i-1]][c[i]]*(1-p[i-1]) 前一个申请不成功
                             +dis[d[i-1]][c[i]]*p[i-1]);  前一个申请成功

同理 当前i课申请,那么就有 四种c[i-1]->c[i]  c[i-1]->d[i] d[i-1]->c[i] d[i]->c[i-1] 各有成功的概率

有点复杂,容易写错。注意一下找找bug就行了

#include<bits/stdc++.h>
using namespace std;
const int N=2e3+10;
int c[N],d[N],dis[310][310];

double p[N],f[N][N],g[N][N];

int main()
{
    int n,m,v,e,x,y,z;
    double ans = 1e9;
    scanf("%d%d%d%d",&n,&m,&v,&e);
    for(int i=1;i<=n;i++) scanf("%d",&c[i]);
    for(int i=1;i<=n;i++) scanf("%d",&d[i]);

    for(int i=1;i<=n;i++) scanf("%lf",&p[i]);

    for(int i=1;i<=v;i++)
    {
        for(int j=1;j<=v;j++) dis[i][j] = 1000000000;
        dis[i][i] = 0;
    }
    for(int i=1;i<=e;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        dis[x][y]=dis[y][x]=min(dis[x][y],z);
    }
    for(int k=1;k<=v;k++)
    for(int i=1;i<=v;i++)
    for(int j=1;j<=v;j++)
    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);

    for(int i=1;i<=n;i++)
    for(int j=0;j<=m;j++)
    f[i][j]=g[i][j]=1e9;
    f[1][0] = g[1][1] = 0;

    for(int i=2;i<=n;i++)
    {
        f[i][0]=f[i-1][0]+dis[c[i-1]][c[i]];
        for(int j=1;j<=m;j++)
        {
            f[i][j]=min(f[i-1][j]+dis[c[i-1]][c[i]] ,
                          g[i-1][j]+dis[c[i-1]][c[i]]*(1-p[i-1])
                                   +dis[d[i-1]][c[i]]*p[i-1]);

            g[i][j] = min(f[i-1][j-1]+dis[c[i-1]][c[i]]*(1-p[i])
                          +dis[c[i-1]][d[i]]*p[i],

                          g[i-1][j-1]
                          +dis[c[i-1]][c[i]]*(1-p[i-1])*(1-p[i])
                          +dis[d[i-1]][c[i]]*p[i-1]*(1-p[i])
                          +dis[c[i-1]][d[i]]*(1-p[i-1])*p[i]
                          +dis[d[i-1]][d[i]]*p[i-1]*p[i]);
        }
    }
    for(int i=0;i<=m;i++)
        ans=min(ans,min(f[n][i],g[n][i]));
    printf("%.2f\n" , ans);
    return 0;
}
发布了498 篇原创文章 · 获赞 66 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/104901364