zoukankan      html  css  js  c++  java
  • 《10.23训练题解》

    A - Article

    这题看着好做但是挺难的。

    dp[i] - 表示打成功了i个字的期望打字数。

    dp[i] = dp[i - 1] + 1 * (1 - p) + (dp[i] + 1) * p;

    这里并没有考虑x的存档操作,所以如果失败了就要重新打dp[i]的字。

    所以就是(dp[i] + 1) * p

    化简一下就是dp[i] = (dp[i - 1] + 1) / (1 - p)

    我们处理完了这里普通的期望次数后。

    可以发现,dp是一个递增的值,所以我们可以分段,考虑每段打了i + x个字后,保存。

    然后取一下最小值就好。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 1e5 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e8
    #define IN_INF 0x3f3f3f3f
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    double dp[N];//打了i个字的期望次数.
    int n,x,caa = 0;
    double cal(int k) {
        int c = n / k;
        return 1.0 * k * x + dp[c + 1] * (n % k) + dp[c] * (k - n % k);
    }
    void solve() { 
        double p;
        cin >> n >> p >> x;
        for(int i = 1;i <= n;++i) {
            dp[i] = (dp[i - 1] + 1) / (1.0 - p);
        }
        double ans = 1000000000000000000;
        for(int i = 1;i <= n;++i) {
            ans = min(ans,cal(i));
        }
        printf("Case #%d: %.6f
    ",++caa,ans);
    }   
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            solve();
        }
        //system("pause");
        return 0;
    }
    View Code

    B:一个模拟题,队友写了,模拟的神。

    D:这题其实不难,观察到模数很特殊,取了一些数试了试,可以发现,最多30次后,a[i]再操作依旧 = a[i]。

    那么线段树维护一下就好,注意这里需要稍微优化掉一些不必要的操作,不然容易T.

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 1e5 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e8
    #define IN_INF 0x3f3f3f3f
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    LL p = 9223372034707292160;
    ULL a[N],ans = 0;
    int caa = 0;
    ULL quick_mul(ULL a,ULL b) {
        ULL re = 0;
        while(b) {
            if(b & 1) re = (re + a) % p;
            a = (a << 1) % p;
            b >>= 1;
        }
        return re;
    }
    struct Node{int L,r,f;ULL val;}node[N << 2];
    void Pushup(int idx) {
        if(node[idx << 1].f && node[idx << 1 | 1].f) node[idx].f = 1;
        node[idx].val = (node[idx << 1].val + node[idx << 1 | 1].val) % p;
    }
    void build(int L,int r,int idx) {
        node[idx].L = L,node[idx].r = r,node[idx].f = 0;
        if(L == r) {
            if(a[L] == 0 || a[L] == 1) node[idx].f = 1;
            node[idx].val = a[L];
            return ;
        }
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
        Pushup(idx);
    }
    void update(int L,int r,int idx) {
        if(node[idx].L >= L && node[idx].r <= r && node[idx].f) {
            ans = (ans + node[idx].val) % p;
            return ;
        }
        if(node[idx].L == node[idx].r) {
            ans = (ans + node[idx].val) % p;
            if(node[idx].f) return ;
            ULL pre = node[idx].val;
            node[idx].val = quick_mul(node[idx].val,node[idx].val);
            if(node[idx].val == pre) node[idx].f = 1;
            return ;
        }
        int mid = (node[idx].L + node[idx].r) >> 1; 
        if(mid >= L) update(L,r,idx << 1);
        if(mid < r) update(L,r,idx << 1 | 1);
        Pushup(idx);
    }
    void solve() { 
        int n,m;scanf("%d %d",&n,&m);
        for(int i = 1;i <= n;++i) scanf("%llu",&a[i]);
        build(1,n,1);
        ans = 0;
        printf("Case #%d:
    ",++caa);
        while(m--) {
            int L,r;scanf("%d %d",&L,&r);
            update(L,r,1);
            printf("%llu
    ",ans);
        }
    }   
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            solve();
        }
        //system("pause");
        return 0;
    }
    View Code

    E:签到

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 1e5 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e8
    #define IN_INF 0x3f3f3f3f
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
      
    int n,caa = 0;
    struct Node{int r,e,L;}p[N];
    bool cmp(Node a,Node b) {
        return a.e < b.e;
    }
    void solve() { 
        scanf("%d",&n);
        for(int i = 1;i <= n;++i) cin >> p[i].r >> p[i].e >> p[i].L;
        sort(p + 1,p + n + 1,cmp);
        int now = 0,f = 0;
        for(int i = 1;i <= n;++i) {
            if(now + p[i].r > p[i].e) f = 1;
            now = p[i].e + p[i].L;
        }
        printf("Case #%d: %s
    ",++caa,f ? "NO" : "YES");
    }   
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            solve();
        }
       // system("pause");
        return 0;
    }
    View Code

    F:这题其实直接推不是很好推,我小数据猜测了一下结论。

    然后写了个java大数就过了。

    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.Scanner;
    
    public class Main {
        public static BigInteger quick_mi(BigInteger a,int b) {
            BigInteger re = new BigInteger("1");
            while(b != 0) {
                if((b & 1) != 0) re = re.multiply(a);
                a = a.multiply(a);
                b >>= 1;
            }
            return re;
        }
        public static void main(String[] args) {
            Scanner input = new Scanner(System.in);
            int ca = input.nextInt();
            for(int i = 1;i <= ca;++i) {
                int n = input.nextInt();
                BigInteger ans = quick_mi(new BigInteger("2"),5 * n);
                System.out.print("Case #");
                System.out.print(i);
                System.out.println(": " + ans);
            }
    
        }
    }
    View Code

    G:这题还是挺不错的,可能状态比较好,看了一会就想到了做法。

    首先,贪心选择每条路,每次都选最大价值的那条,然后删掉路上的所有价值。

    我的做法是:维护根到每个叶子节点的路径总价值,然后dfs序维护线段树。

    可以发现,我们删去一个点的代价就是删去这个点子树内所有点的值,那么做一下子树的区间更新即可。

    然后这里我们做一个优化,我们从下往上去删每个点的代价(这里暴力向上就行),然后我们标记一下每个点有没有被删去。

    如果一个点被删去了,它往上都肯定被删过,就不用再走了。这样保证了每个点只被更新一下,复杂度就是nlogn。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 1e5 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e8
    #define IN_INF 0x3f3f3f3f
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    int v[N],sz[N],dfn[N],rk[N],fa[N],tim = 0,caa = 0;
    bool vis[N];
    vector<int> G[N];
    LL val[N];
    void dfs(int u,int ffa) {
        dfn[u] = ++tim;
        fa[u] = ffa;
        rk[tim] = u;
        val[u] = val[ffa] + v[u];
        sz[u] = 1;
        for(auto v : G[u]) {
            dfs(v,u);
            sz[u] += sz[v];
        }
    }
    void init() {
        tim = 0;
        memset(vis,0,sizeof(vis));
    }
    struct Node{int L,r;LL mx,tag,pos;}node[N << 2];
    void Pushdown(int idx) {
        if(node[idx].tag) {
            node[idx << 1].mx -= node[idx].tag;
            node[idx << 1 | 1].mx -= node[idx].tag;
            node[idx << 1].tag += node[idx].tag;
            node[idx << 1 | 1].tag += node[idx].tag;
            node[idx].tag = 0;
        }
    }
    void Pushup(int idx) {
        if(node[idx << 1].mx > node[idx << 1 | 1].mx) {
            node[idx].mx = node[idx << 1].mx;
            node[idx].pos = node[idx << 1].pos;
        }
        else {
            node[idx].mx = node[idx << 1 | 1].mx;
            node[idx].pos = node[idx << 1 | 1].pos;
        }
    }
    void build(int L,int r,int idx) {
        node[idx].L = L,node[idx].r = r,node[idx].tag = 0;
        if(L == r) {
            node[idx].mx = val[rk[L]];
            node[idx].pos = rk[L];
            return ;
        }
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
        Pushup(idx);
    }
    void update(int L,int r,int val,int idx) {
        if(node[idx].L >= L && node[idx].r <= r) {
            node[idx].mx -= val;
            node[idx].tag += val;
            return ;
        }
        Pushdown(idx);
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= L) update(L,r,val,idx << 1);
        if(mid < r) update(L,r,val,idx << 1 | 1);
        Pushup(idx);
    }
    void del(int x) {
        while(1) {
            if(vis[x] == 1 || x == 0) break;
            update(dfn[x],dfn[x] + sz[x] - 1,v[x],1);
            vis[x] = 1;
            x = fa[x];
        }
    }
    void solve() { 
        init();
        int n,k;scanf("%d %d",&n,&k);
        for(int i = 1;i <= n;++i) scanf("%d",&v[i]),G[i].clear();
        for(int i = 1;i < n;++i) {
            int x,y;scanf("%d %d",&x,&y);
            G[x].push_back(y);
        }
        dfs(1,0);
        build(1,tim,1);
        LL ans = 0;
        for(int i = 1;i <= k;++i) {
            ans += node[1].mx;
            del(node[1].pos);
        }
        printf("Case #%d: %lld
    ",++caa,ans);
    }   
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            solve();
        }
       // system("pause");
        return 0;
    }
    View Code

    I:队友做出来了,说是找规律加分治,真狠呐。

    J:这题我想错方向了。一直在考虑对次数dp。

    其实它每次选点和上一次选的是没有概率影响的。

    我们可以考虑每个点的概率,p[i][j] - 表示(i,j)至少被选中一次的概率,最后所有加一下就是期望了。

    这里我们考虑一下怎么求(i,j)至少被选中一次的概率。很显然容斥。我们算一次都没选中的概率。

    我们发现只要两个点在同侧就可以保证不被选中。不过这样四个角落会被重复选中,所以要减去。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 1e5 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e8
    #define IN_INF 0x3f3f3f3f
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    double dp[505][505];//dp[i][j] - k次后选中(i,j)的概率
    int caa = 0;
    double cal(double x,int k) {
        double ans = 1.0;
        for(int i = 1;i <= k;++i) ans = ans * x;
        return ans;
    }
    void solve() { 
        int m,n,k;scanf("%d %d %d",&m,&n,&k);
        double ans = 0;
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= m;++j) {
                LL p = 1LL * n * (j - 1) * n * (j - 1);//全在左侧
                LL p1 = 1LL * n * (m - j) * n * (m - j);//全在右侧
                LL p2 = 1.0 * m * (i - 1) * m * (i - 1);//全在上侧
                LL p3 = 1.0 * m * (n - i) * m * (n - i);//全在下侧
                LL c1 = 1.0 * (i - 1) * (j - 1) * (i - 1) * (j - 1);//左上角
                LL c2 = 1.0 * (n - i) * (j - 1) * (n - i) * (j - 1);//左下角
                LL c3 = 1.0 * (i - 1) * (m - j) * (i - 1) * (m - j);//右上角
                LL c4 = 1.0 * (n - i) * (m - j) * (n - i) * (m - j);//右下角
                LL f = p + p1 + p2 + p3 - c1 -c2 -c3 -c4;
                dp[i][j] = f * 1.0 / (1LL * n * n * m * m);
                ans += 1.0 - cal(dp[i][j],k);
            }
        }
        printf("Case #%d: %d
    ",++caa,(int)round(ans));
    }   
    int main() {
        int ca;scanf("%d",&ca);
        while(ca--) {
            solve();
        }
        //system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    Shell printf 命令
    Shell echo命令
    Shell 基本运算符
    Shell 数组
    Shell 传递参数
    Shell 变量
    Spark基础知识汇总
    DataScientist————汇总篇
    Java的Unsafe类
    java 中文字符和unicode编码值相互转化
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15450397.html
Copyright © 2011-2022 走看看