2018.07.20【2018提高组】模拟C组

前言:从未绝望的一天


JZOJ 3388 绿豆蛙的归宿

题目

给出一个有向无环图,起点为1终点为N,每条边都有一个长度,并且从起点出发能够到达所有的点,所有的点也都能够到达终点。从起点走向终点,到达每一个顶点时,如果有K条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 1/K 。求从起点走到终点的所经过的路径总长度期望。


分析

f [ x ] 表示从节点 x 走到终点所经过的路径的期望长度,那么根据数学期望的定义和性质,得 f [ x ] = 1 k i = 1 k ( f [ n e x t i ] + d i s [ x ] [ n e x t i ] ) ,两种方法,一种正向深搜,还有反向广搜,各有优缺,then


代码

#include <cstdio>
#include <cctype>
using namespace std;
struct node{int y,w,next;}e[200001];
int ls[100001],deg[100001],n,m;
int in(){
    int ans=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans;
}
double dfs(int x){
    double ans=0; if (!ls[x]) return 0;
    for (int i=ls[x];i;i=e[i].next) ans+=(dfs(e[i].y)+e[i].w)*1.0/deg[x];
    return ans;
}
int main(){
    n=in(); m=in(); int x;
    for (int i=1;i<=m;i++){
        x=in(); e[i].y=in(); e[i].w=in();
        deg[x]++; e[i].next=ls[x]; ls[x]=i;
    } 
    return !printf("%.2lf",dfs(1));
}

JZOJ 3467 最长上升子序列

题目:可持久化LIS

分析:离线处理,用O(nlogn)的时间求LIS


代码

#include <cstdio>
#include <cctype>
#include <stack>
#define N 500001
using namespace std;
int a[N],pnt[N],ans[N],ls[N],nxt[N]; bool flag[N];
int len,n,l,rem[N],p[N],id[N],b[N],c[N]; stack<int>st;
int in(){
    int ans=0; char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans;
}
void add(int x,int y){nxt[++l]=ls[x]; ls[x]=l; rem[l]=y;}
void dfs(){
    p[0]=-1; int length=0;
    id[0]=ls[0]; st.push(0);
    while (st.size()){
        if (!id[st.top()]){//没有出现
            int t=st.top(); st.pop();
            if (!flag[t]) length--;//不是答案
            else p[b[t]]=c[t];//记录
        }
        else{
            int t=rem[id[st.top()]];
            id[st.top()]=nxt[id[st.top()]];
            st.push(t); id[t]=ls[t];
            if (a[t]>p[length]) flag[t]=0,p[++length]=a[t];//超过了长度
            else{
                flag[t]=1;//需要找答案
                int l=0,r=length+1;
                while (l<r){//二分查找
                    int mid=(l+r)>>1;
                    if (a[t]>p[mid]) l=mid+1;
                    else r=mid;
                }
                b[t]=l; c[t]=p[l]; p[l]=a[t];
            }
            ans[t]=length;
        }
    }
}
void print(int ans){if (ans>9) print(ans/10); putchar(ans%10+48);}
int main(){
    freopen("lis.in","r",stdin);
    freopen("lis.out","w",stdout);
    bool x; int y,now=0; n=in();
    for (int i=1;i<=n;i++){
        x=in(); y=in();
        if (!x) add(now,++len),a[(now=len)]=y; //全新版本
        else now=pnt[y]; pnt[i]=now;//当前版本
    }
    dfs();
    for (int i=1;i<=n;i++,putchar('\n')) 
    if (ans[pnt[i]]) print(ans[pnt[i]]); else putchar('0');
    return 0;
}

JZOJ 3468 osu!

题目

在长度为 n 的01串中,若连续的 x 个1可得到 x 3 的分数,每个位置选择1都有概率,问期望得到的分数。


分析

动态规划, f [ i ] 表示前 i 位且第 i 位为1的期望得到的分数,根据完全立方公式 ( a + b ) 3 = a 3 + 3 a 2 b + 3 a b 2 + b 3 ,可以在每一位处理当前的答案。


代码

#include <cstdio>
using namespace std;
int n; double d,f,g,h;
int main(){
    freopen("osu.in","r",stdin);
    freopen("osu.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;i++){
        scanf("%lf",&d);
        f+=d*(3*(h+g)+1);//乘概率
        h=d*(h+2*g+1);
        g=d*(g+1);
    }
    return !printf("%.1lf",f);
}

JZOJ 3389 Heaven Cow与God Bull

题目:求 m n ,使 m ÷ φ ( m ) 最大。

分析:

φ ( m ) = m Π p | m p 1 p
所以 m ÷ φ ( m ) = m m Π p | m p 1 p
也就是 Π p | m p 1 p 需要最小,说明质数的个数要尽量多,所以就是最小值最大(最大是因为质数个数多说明要大),所以离线+二分,具体如何优化?
由于比较懒,所以eratosthenes筛法,我的优化是质数2时提前处理(特判n是1)然后偶数就可以不理它了,所以大概就是 O 28890 l o g l o g 28890 67295
问题是还要高精度乘单精度,所以压16位(不想再压了,不然炸了就不好了),共 O ( 4643559 ) 也很大了,突然发现在线查询超时是必然的,之后离线完二分查找,大概就是 O ( 100 5852 l o g 5852 5076340 ) ,最后总计 O ( 9719899 ) ,end


代码

#include <cstdio>
#define mod 10000000000000000
typedef long long ll; typedef unsigned short ust; char n[25001];
ll ans[5853][1563],a[1563]; ust tot=0,len[5853]; bool v[28891]; int len2;
bool check(int x){
    if (len[x]!=(len2+1)) return len[x]<(len2+1);
    for (ust i=len2;i;i--)
        if (ans[x][i]!=a[i]) return ans[x][i]<a[i];
    return ans[x][0]<=a[0];
}
void out(ll ans){if (ans>9) out(ans/10); putchar(ans%10+48);}
void print(ust x){
    for (int i=len[x]-1;i>=0;i--){
        ll k=mod/10;
        if (i!=len[x]-1)
        while (ans[x][i]<k&&k>1) putchar('0'),k/=10;
        if (ans[x][i]) out(ans[x][i]);
    }
    putchar('\n');
}
int main(){
    ans[0][len[0]++]=2ll;
    for (ust i=1;i<=28890;i++)//eratosthenes筛法
        if (!v[i]){
            ust k=i<<1|1; len[++tot]=len[tot-1]; ll s,g=0,h;
            for (ust j=0;j<len[tot];j++){//压16位高精度
                h=((long double)ans[tot-1][j]*k+g)/mod;//求商
                s=ans[tot-1][j]*k+g-h*mod;
                if (s<0) s+=mod; else if (s>=mod) s-=mod;
                ans[tot][j]=s; g=h;
            }
            while (g) ans[tot][len[tot]++]=g%mod,g/=mod;
            for (ust j=i;j<=28890/k;j++) v[k*(j<<1|1)>>1]=1;//诡异的筛法
        }
    char c=getchar(); ust t=0,len1; ll k;
    while (c<48||c>57) c=getchar();
    while (c>=48&&c<=57) t=t*10+c-48,c=getchar();
    while (t--){
        c=getchar(); len1=len2=0; k=1; ust j=0; a[0]=0;
        while (c<48||c>57) c=getchar();
        while (c>=48&&c<=57) n[++len1]=c,c=getchar();
        for (ust i=len1;i>=1;i--){//压16位存储
            j++;  a[len2]+=(n[i]-48)*k;
            k=(k<<1)+(k<<3); if (j==16) j=0,k=1,a[++len2]=0; 
        }
        if (!j) len2--; if (!len2&&a[len2]==1) {putchar('1'); continue;}
        ust l=0,r=tot;
        while (l<r){//二分
            ust mid=(l+r+1)>>1;
            if (check(mid)) l=mid; else r=mid-1;
        }
        print(l);
    }
    return 0;       
}

后续

洛谷 4316 codevs 2488 绿豆蛙的归宿 洛谷 1654 osu!

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/81150537
今日推荐