• ysj的模拟赛


    链接:https://www.luogu.org/problemnew/show/P4917

    天守阁的地板

    题目描述

    为了使万宝槌能发挥出全部魔力,小碗会将买来的地板铺满一个任意边长的正方形(地板有图案,因此不允许旋转,当然,地板不允许重叠)来达到最大共鸣

    现在,她能够买到规格为a∗ba*bab的地板,为了省钱,她会购买尽可能数量少的地板

    现在,她想知道对于每一对a,b(1≤a,b≤n)a,b(1≤a,b≤n)a,b(1a,bn),她最少需要购买的地板数量

    由于输出可能很大,所以你只需要输出所有答案的乘积即可,为了避免高精度,小碗很良心的让你将答案对192608171926081719260817取模

    输入输出格式

    输入格式:

    第一行一个整数TTT,表示数据组数
    下面TTT行,每行一个整数nnn

    输出格式:

    TTT行,每行一个整数,表示取模后的答案

    输入输出样例

    输入样例#1: 复制
    4
    1
    2
    3
    100
    输出样例#1: 复制
    1
    4
    1296
    18996121

    说明

    样例解释:
    对于n=1,a,b仅有(1,1)(1,1)(1,1一种情况,只需要一块1∗1的地板,答案为1

    对于n=2,a,b(1,1),(1,2),(2,1),(2,2)四种情况,分别需要一块(1∗1)两块(1∗2),两块(2∗1),一块(2∗2)的地板,答案为1∗2∗2∗1=41*2*2*1=41221=4

    追加解释:a,b有四种取值,分别是(1,1),(1,2),(2,1),(2,2)

    当只能买到1∗1的地板时,需要一块(本身就是正方形)
    当只能买到1∗2的地板时,需要两块(两块拼在一起组成2∗2的正方形)
    当只能买到2∗1的地板时,需要两块(两块拼在一起组成2∗2的正方形)
    当只能买到2∗2的地板时,需要一块(本身就是正方形)

    答案就是这些数的乘积,即444

    T<=100, n <=1e6

    题解:一道非常好的数论题

    主要涉及了两个知识点(都做过,但并没有想到结合):

    第一个,求gcd(x, y) = d, x,y <= n 的对数,详见:https://www.cnblogs.com/EdSheeran/p/9329517.html

    第二个,乘除分块,详见:https://www.cnblogs.com/EdSheeran/p/9470009.html

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    const int M = 1e6 + 5;
    const LL mod = 19260817;
    LL sum[M],fac[M];
    int vfac[mod + 1]; 
    bool vis[M]; 
    int phi[M],  tot, prime[M];
    LL ksm(LL a, LL b){
        LL ret = 1;
        for(;b;b>>=1,a=a*a%mod)
            if(b&1)ret=ret*a%mod;
        return ret;
    }
    
    
    void pre(){
        fac[0] = vfac[0] = vfac[1] = 1;
        
        for(int i = 1; i < M; i++)
            fac[i] = fac[i - 1] * i % mod;
        for(int i = 2; i < mod; i++)
            vfac[i] = (-(LL)(mod/i) * vfac[mod%i] % mod + mod) % mod;
        
        phi[1] = 1;
        for(int i = 2; i < M; i++){
            if(!vis[i]) phi[i] = i - 1, prime[++tot] = i;
            for(int j = 1; j <= tot && (LL)i * prime[j] < M; j++){
                int m = i * prime[j];
                vis[m] = 1;
                if(i % prime[j] == 0){// if n%i == 0 phi[n*i] = phi[n] * i;
                    phi[m] = phi[i] * prime[j];
                    break;
                }
                phi[m] = phi[i] * phi[prime[j]];
            }
        }
        for(int i = 1; i < M; i++)sum[i] = sum[i - 1] + phi[i];
    }
    
    
    
    int main(){
        int T;
        scanf("%d", &T);
        pre();
        while(T--){
            int n;
            scanf("%d", &n);
            LL ans1 = ksm(fac[n], 2*n);
            LL ans2 = 1;
            for(int i = 1, rg; i <= n;){
                rg = n/(n/i);
                LL p = sum[n/i];
                ans2 = ans2* ksm(fac[rg]*(LL)vfac[fac[i-1]]%mod, 2*p-1) % mod;
                i = rg + 1;
            }
            ans2=ans2*ans2%mod;
            ans1 = ans1 * (LL)vfac[ans2]%mod;
            printf("%lld
    ", ans1);
        }
    }
    View Code

    4918 信仰收集

    输入样例#1: 复制
    3 7 8
    1 2
    3 2
    2 2
    4 3
    6 4
    1 2
    2 4
    4 5
    2 6
    7 6
    6 4
    3 2
    3 4
    输出样例#1: 复制
    2

     

    题解:dp[u][j]表示当前在u号节点,这段瞬移还有j才结束的最大收益;

    虽然dp方程我想出来了,但是实际操作我遇到了问题;

    一是怎么确定遍历顺序,我做了一遍SPFA,从距离大的倒着更新;(这应该是有问题的,而且常数大)

    二是我瞬移的花费与收获在出发时还是结束时计算;

    看了std,第一个问题可以用拓扑排序解决,通过入度更新,这样是显然正确的;

    第二个是在出发时减去花费,到达时加上当前点的贡献,不重不漏;

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int M = 2e5 + 10, ME = 3e5 + 10, inf = -2e9;
    
    int dp[M][52], d[2], w[2], here[M], deg[M];
    queue <int> q;
    struct edge{int v, nxt;}G[ME];
    int tot,cnt,dis[M],hh[M],h[M],a[M];
    bool inq[M];
    void add(int u, int v){
        G[++tot].v=v,G[tot].nxt=h[u],h[u]=tot;
    }
    
    int read(){
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*=f;
    }
    #define ex(i, u) for(int i = h[u]; i; i = G[i].nxt)
    void del(int u){
        ex(i, u){
            int v = G[i].v;
            deg[v]--;
            if(!deg[v] && v!=1)q.push(v);
        }
    }
    
    int main(){
        int u, v, n, m, k;
        scanf("%d%d%d", &n, &m, &k);
        scanf("%d%d%d%d", &d[0], &d[1], &w[0], &w[1]);
        for(int i = 1; i <= n; i++){
            u = read(), v = read();
            here[u] += v;
        }
        for(int i = 1; i <= k; i++){
            u = read(), v = read();
            add(u, v); deg[v]++; 
        }
        
        for(int i = 2; i <= m; i++)
            if(!deg[i])q.push(i);
        while(!q.empty()){
            int u=q.front();q.pop();
            del(u);
        }// the useless vertex
        q.push(1);
        memset(dp, 0x8f, sizeof(dp));
        dp[1][0] = here[1];
        while(!q.empty()){
            int u=q.front();q.pop();
            del(u);
            ex(i, u){
                int v=G[i].v;
                if(dp[u][0] > inf){
                    if(d[0]!=1) dp[v][d[0]-1] = max(dp[v][d[0]-1], dp[u][0] - w[0]);
                    else dp[v][0] = max(dp[v][0], dp[u][0] - w[0] + here[v]);
                    if(d[1]!=1)  dp[v][d[1]-1] = max(dp[v][d[1]-1], dp[u][0] - w[1]);
                    else dp[v][0] = max(dp[v][0], dp[u][0] - w[1] + here[v]);
                    
                }        
                if(dp[u][1] > inf)dp[v][0] = max(dp[v][0], dp[u][1] + here[v]);
                for(int j=1; j<d[1]; j++){
                    dp[v][j] = max(dp[v][j], dp[u][j+1]);
                }
            }
        }
        int ans = 0;
        for(int i = 1; i <= m; i++) ans = max(ans, dp[i][0]);
        printf("%d
    ", ans);
        
    }
    View Code
  • 相关阅读:
    IOS 自动布局-UIStackPanel和UIGridPanel(三)
    IOS 自动布局-UIStackPanel和UIGridPanel(二)
    IOS 自动布局-UIStackPanel和UIGridPanel(一)
    我的新博客
    Topcoder SRM655 DIV1 500 Nine
    BestCoder Round #38 1002 Greatest Greatest Common Divisor 筛法
    BestCoder Round #38 1001 Four Inages Strategy 暴力
    Google Code Jam 2015 Round 1A Haircut 二分
    Google Code Jam 2015 Round 1A Mushroom Monster 水
    Topcoder SRM656 DIV1 250 RandomPancakeStack 概率DP
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9757297.html
Copyright © 2020-2023  润新知