2023.8.16

E - Roulettes (atcoder.jp)

题意:给定n个轮盘,轮盘有pi个数字,花费ci元转它,等概率停在某个数字,你将获得该数字的积分

求达到m积分的最小期望值

思路:定义dp[i]表示已经得到积分i,为达到m积分的最小花费,

枚举转盘,再枚举转盘的数字,对应后继状态,

若转盘为2,4,6,8则dp[i]=ci+(1/4)*dp[i+2]+(1/4)*dp[i+4]+(1/4)*dp[i+6]+(1/4)*dp[i+8]

同时消除0,若为0,4,6,8则dp[i]=ci+(1/4)*dp[i]+(1/4)*dp[i+4]+(1/4)*dp[i+6]+(1/4)*dp[i+8]移项的dp[i]=(4/3)*c[i]+(1/3)*dp[i+4]+(1/3)*dp[i+6]+(1/3)*dp[i+8]

int n,m;

vectorv[N];
double c[N];
double dp[N];
void solve(){
    cin>>n>>m;
    fr(i,1,n){
        cin>>c[i];
        int x;
        cin>>x;
        int cnt=0;
        fr(j,1,x){
            int y;
            cin>>y;
            if(y==0){
                cnt++;
            }
            else{
                v[i].push_back(y);
            }
        }
        c[i]=1.0*c[i]*x/(x-cnt);
    }
    ufr(i,m-1,0){
       double ans=inf;
       fr(j,1,n){
          double t=0;
          for(auto k:v[j]){
             t+=(i+k>=m?0:dp[i+k])+c[j];
          }
          t/=v[j].size();
          ans=min(ans,t);
       }
       dp[i]=ans;
    }
     printf("%.10lf",dp[0]);
}

signed main()
{
    int t=1;
 //   cin>>t;
    while(t--) solve();
    return 0;
}

规律:

1.两数相减,相加的最大,最小值

2.由最初的状态递推

3.无强制顺序,排序

4.对于一段等差数列,不用一段一段的算局部整体,可以从整体一步步加差值

5.需要从一段式子推到结果困难,将结果反推式子,(从结果的需要特性式子需要全部满足)

6.式子移项。式子消去

7.将一步步走到结果,反推到能走到这个结果一定会存在什么步骤

8.枚举两个位置,当一个位置可由另一个位置一个条件推出时,一个位置即可

9.删边最小=加边最大

10.隔板法:C(m-1,n-1),

11.统计区间的值,当前状态取决于上一个状态与当前值,dp[当前位置][结果可能]=数量

12.一个后面情况全由第一个决定,枚举第一个所有情况

13.分类,一共有少数个类别,由少数个类别组成的多个数,分类

14.一个数的改变对前面有影响或对后面有影响

算法

1.点到线段的最短距离公式

2.bfs求最短路(在n*m的图上,套用spfa板子)

3.树的深度

4.bitset优化

5.dp二维,一维位置,二维所有可能结果

6.取石子的sg函数打表

7.带权并查集的关系维护,并查集(子树合并:节点数)

8.基环内向树(特点:从任意一个点出发,必定会跑到环内)

9.最短路或最长路分层图的建立,路径上最大值最小(边权传递),相遇问题:枚举相遇点+反向最短路

10.最小生成树:每个结点多个选择,多建多个源点与之相连

11.记忆化

12.树状数组+离散化维护区间移项

13.期望dp

14.sg打表,sg函数(拿l~r)

你可能感兴趣的:(算法)