SRM548 Div1Medium KingdomAndDice

来源:互联网 发布:回到2005年txt下载知轩 编辑:程序博客网 时间:2024/06/06 19:48

解题思路

首先显然要先对{bn}进行排序
而对于某一个值q[bi+1bi+11],它对答案的贡献是相同的
于是对于每个等于ai=0,只会变成最多2n个数,这样就可以dp
当然博主因为比较懒,直接每个区间存了n个数,复杂度依然不超
当然,你还需要储存一下这个数所代表的区间有多长,然后算出对答案的贡献
我们定义dpj为所有的ai=0对答案的贡献为j时使用的ai=0的最少数量
显然dp转移是很轻易的:
dpj=min(dpjdp[jSi]+1)
//Si即上述[bj+1bj+11]区间中的任意一个数或ax
然后最后我们可以用dpi来更新答案:
即当dpi<=m时,
abs(2(i+sum)nn)<abs(2ansnn)
ans<-sum
(原先O(n3),博主O(n4)
代码如下:

#include<bits/stdc++.h>using namespace std;#define M 20005int dp[M];vector<int>A,B,S;set<int>numA;int main(){    int n;    scanf("%d",&n);    for(int i=1;i<=2*n;i++){        int x;        scanf("%d",&x);        if(i<=n)A.push_back(x);        else B.push_back(x);    }    int X;    scanf("%d",&X);    for(int i=0;i<n;i++)numA.insert(A[i]);    B.push_back(0);B.push_back(X+1);    sort(B.begin(),B.end());    int m=0,sum=0;    for(int i=0;i<n;i++){        m+=A[i]==0;        for(int j=1;j<=n;j++)            sum+=A[i]>B[j];    }    for(int i=0;i<=n;i++)        for(int j=B[i]+1,c=0;j<B[i+1]&&c<n;j++,c++)            if(numA.find(j)==numA.end()){                int cnt=0;                for(int k=1;k<=n;k++)cnt+=B[k]<j;                S.push_back(cnt);            }//预处理    dp[0]=0;    for(int i=1;i<=n*n;i++)dp[i]=m+1;    for(int i=0;i<S.size();i++)        for(int j=n*n;j>=1;j--)            if(j-S[i]>=0)dp[j]=min(dp[j],dp[j-S[i]]+1);//dp    int res=-1;    for(int i=0;i<=n*n;i++)        if(dp[i]<=m)            if(res==-1||abs(2*(i+sum)-n*n)<abs(2*res-n*n))                res=i+sum;//更新答案    printf("%.8f\n",1.0*res/n/n);    return 0;}
2 0
原创粉丝点击