这个题首先要利用题目的特性,先贪心,否则无法进行DP
因为求期望的话,越后面的乘的越大,所以为了得到最小值,应该把概率值降序排序,把大的数跟小的系数相乘
然后这种dp的特性就是转移的时候,由 i推到i+1每次添加一个数,就要考虑这个新数应该和谁放在一组,枚举他放在哪一组即可
dp[i][j]代表当前第i个数有j个分组时候的最小值
dp[i][j]=dp[k][j-1]+i(prefix[i]-prefix[k-1]),k代表枚举第几个数开始和当前新添加的数为一组,prefix为前缀和,为了迅速得出区间和
注意边界处理和一些细节
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #include <set> #define LL __int64 using namespace std; struct node { int x,y; bool operator < (const node&rhs) const { if (x==rhs.x) return y<rhs.y; return x<rhs.x; } }tasks[100010]; bool cmp(node a,node b) { if (a.x==b.x) return a.y<b.y; return a.x<b.x; } int n,m; multiset<node> v; multiset<node>::iterator it; /* int bs(int p,int q) { int L=0,R=v[p].size(),mid; while (L<R) { mid=(L+R)>>1; if (v[p][mid]<tasks[q].x) L=mid+1; else R=mid; } return L; } */ int main() { int a,b; while (scanf("%d%d",&m,&n)!=EOF) { int maxn=0; v.clear(); for (int i=1;i<=m;i++){ scanf("%d%d",&a,&b); v.insert((node){a,b}); maxn=max(b,maxn); } for (int i=1;i<=n;i++){ scanf("%d%d",&a,&b); tasks[i].x=a; tasks[i].y=b; } sort(tasks+1,tasks+1+n); //for (int i=0;i<=maxn;i++) sort(v[i].begin(),v[i].end()); LL ans=0; int sum=0; for (int i=n;i>=1;i--){ it=v.lower_bound(tasks[i]); if (it==v.end()) continue; else{ v.erase(it); ans+=(LL)tasks[i].x*500+(LL)tasks[i].y*2; sum++; } } printf("%d %I64d ",sum,ans); } return 0; }