《小白月赛25》部分题解

D:
思路:概率论.
计算出每个卡池拿不到的概率,最后1-即可.
注意1-之后可能会<0,所以要加上模数再取模.
这里的概率计算直接上逆元就可以了.
小细节:ma *= a%mod,是不对的这样本质上是先对a取模再乘ma.这样存在爆精度的问题.
Code:

LL quick(LL a,LL b)
{
    LL re = 1;
    while(b)
    {
        if(b&1) re = (re*a)%Mod;
        b >>= 1;
        a = (a*a)%Mod;
    }
    return re;
}
LL a[N],b[N];
int main()
{
    int n;sd(n);
    for(int i=1;i<=n;++i) sld(a[i]);
    for(int i=1;i<=n;++i) sld(b[i]);
    LL ma = 1;
    for(int i=1;i<=n;++i)
    {
        ma = ma*(a[i]-b[i])%Mod;
        ma = ma*quick(a[i],Mod-2)%Mod;
    }
    printf("%lld\n",(Mod+(1-ma))%Mod);
    system("pause");
    return 0;
}

G:
思路:
很显然这个函数是个单调递增函数.
那么可以直接二分。精度需要扣的比较准,直接循环二分,循环次数开稍微大点。
注意:边界L应该为-INF,因为x可能为负数.二分时按照L = mid,r = mid来,L = mid+1会导致精度丢失..
Code:

double eps = 1e-8;
double a,b,c;
bool cal(double x)
{
    double ma = 1;
    for(int i=1;i<=a;++i) ma *= x;
    ma += b*log(x);
    if(ma-c <= eps) return 1;
    return 0;
}
int main()
{
    cin >> a >> b >> c;
    double L = -INF,r = INF,ans = -INF;
    for(int i=1;i<=1000;++i)
    {
        double mid = (L+r)/2;
        if(cal(mid)) 
        {
            ans = mid;
            L = mid;
        }  
        else r = mid;
    }
    if(ans == -INF) printf("-1\n");
    else printf("%.8f\n",ans);
    //system("pause");
    return 0;
}

J:
思路:位运算。
统计每个二进制位的1和0的个数.
显然,能使这个二进制位不为0的三元组选法只有1 1 1和1 0 0.
然后就能判断了。
注意点:slove函数难以实现对0的个数统计,因为如果初始为0,直接就退出.
所以可以只统计1的个数,然后剩下的0的个数就是n-num1.
Code:

LL a[N],b[61];//1
void slove(LL x)
{
    for(int i=0;x;++i)
    {
        int ma = x%2;
        if(ma&1) b[i]++;
        x /= 2;
    }
}
LL quick_mi(LL a,LL b)
{
    LL re = 1;
    while(b)
    {
        if(b&1) re = (re*a)%Mod;
        b >>= 1;
        a = (a*a)%Mod;
    }
    return re;
}
LL C(LL n,LL m)
{
    LL re = 1;
    for(int i=1;i<=m;++i) 
    {
        re = re*1LL*(n-i+1)%Mod;
        re = re*quick_mi(i,Mod-2)%Mod;
    }
    return re;
}
int main()
{
    int n;sd(n);
    for(int i=1;i<=n;++i) 
    {
        sld(a[i]);
        slove(a[i]);
    }
    LL ans = 0;
    for(int i=0;i<=63;++i)
    {
        if(b[i] >= 3) 
        {
            LL ma = (1LL<<i)%Mod*C(b[i],3)%Mod;
            ans = (ans+ma)%Mod;
        }
        if(b[i] >= 1 && b[i] >= 2)
        {
            LL ma = (1LL<<i)%Mod*b[i]%Mod*C(n-b[i],2)%Mod;
            ans = (ans+ma)%Mod;
        }
    }
    plr(ans);
  //  system("pause");
    return 0;
}

C:
思路1:
像兰子姐的题解那样统计白色连通块,并查集合并..然后搞一搞就行了.
思路2:树形dp.
显然对于最后的结果,肯定是要把某个黑染成白更优.
那么定义dp[i][0]为i点向上的白色连通块数量(不包含i),dp[i][1]为i点向下的白色连通块数量(包含i).
显然,如果点u的子节点v为白色,那么dp[u][1] += dp[v][1].
然后再来思考向上的白色怎么求.
首先要向上,肯定保证它的父节点为白***r>那么肯定dp[u][0] += dp[fa][0].
但这很显然是不完全的,因为fa的子节点和fa相连的白色连通块,也是和u相连的(保证fa为白色的前提下)
那么我们再加上dp[fa][1].
这里有了重复,u点往下的数量本身已经被统计在了dp[fa][1]里。所以我们应该减去.
但这里也是有条件的,那就是确保u为白色,因为u不为白色就不会被加在dp[fa][1]里。
Code:

int n,ans = -1,clo[N];//1-白,0-黑
int dp[N][2];//dp[i][0]向上的白色连通块数量(不包含自己),dp[i][1]向下的白色连通块数量(包含自己).
vector<int> G[N];
void dfs1(int u,int fa)
{
    if(clo[u] == 1) dp[u][1] = 1;
    for(auto v:G[u])
    {
        if(v == fa) continue;
        dfs1(v,u);
        if(clo[v] == 1) dp[u][1] += dp[v][1];
    }
}
void dfs2(int u,int fa)
{
    if(clo[fa] == 1)
    {
        dp[u][0] += dp[fa][0];
        dp[u][0] += dp[fa][1];
        if(clo[u] == 1) dp[u][0] -= dp[u][1];
    }
    for(auto v:G[u])
    {
        if(v == fa) continue;
        dfs2(v,u);
    }
    if(clo[u] == 0) ans = max(ans,dp[u][0]+dp[u][1]+1);
    else ans = max(ans,dp[u][0]+dp[u][1]);
}
int main()
{
    sd(n);
    char s[N];scanf("%s",s+1);
    int num = 0;
    for(int i=1;i<=n;++i) clo[i] = (s[i] == 'W');
    for(int i=1;i<=n;++i) if(clo[i] == 1) num++;
    for(int i=1;i<n;++i)
    {
        int x,y;sdd(x,y);
        G[x].pb(y),G[y].pb(x);
    }
    if(num == n) pr(num);
    else
    {
        dfs1(1,0);
        dfs2(1,0);
        pr(ans);
    }
    system("pause");
    return 0;
}

B:
思路:隔板排列.
一开始觉得直接隔板会有重复..
但是其实并不会,因为有b的存在,所以会使所有排列的情况呈现唯一性.
首先对于最终的排列肯定是
a b a b a b ..
或者b a b b a b..的形式.
那么我们开始先隔板求出a的所有排列方式,然后再隔板求出b的所有排列方式.
然后相乘就是这种方式的总方案数.
因为对于每一种的a的排列方式,和每一种b的排列方案组合之后都不会和别的重复。所以是可行的.
分类讨论下即可.
k为偶:
a b a b a b.
C(n-1,k/2-1).
C(m-1,k/2-1).
b a b a b a.
C(n-1,k/2-1).
C(m-1,k/2-1).
k为奇:
a b a b a b a.
C(n-1,k/2).
C(m-1,k/2-1).
b a b a b a b.
C(n-1,k/2-1).
C(m-1,k/2).
*/
Code:

LL f[N];
void init()
{
    f[0] = 1;for(int i=1;i<N;++i) f[i] = f[i-1]*i%Mod;
}
LL quick_mi(LL a,LL b)
{
    LL re = 1;
    while(b)
    {
        if(b&1) re = re*a%Mod;
        b >>= 1;
        a = a*a%Mod;
    }
    return re;
}
LL C(LL n,LL m)
{
    if(n < m) return 0;
    return f[n]*quick_mi(f[m],Mod-2)%Mod*quick_mi(f[n-m],Mod-2)%Mod;
}
int main()
{
    init();
    int n,m,k;sddd(n,m,k);
    if(n+m < k) printf("0\n");
    else
    {
        if(k&1)//奇数
        {
            LL ma1 = C(n-1,k/2)*C(m-1,k/2-1)%Mod;
            LL ma2 = C(n-1,k/2-1)*C(m-1,k/2)%Mod;
            LL ans = (ma1+ma2)%Mod;
            plr(ans);
        }
        else
        {
            LL ans = C(n-1,k/2-1)*C(m-1,k/2-1)%Mod*2%Mod;
            plr(ans);
        }
    }
    system("pause");
    return 0;
}
全部评论

相关推荐

10-07 23:57
已编辑
电子科技大学 Java
八街九陌:博士?客户端?开发?啊?
点赞 评论 收藏
分享
微风不断:兄弟,你把四旋翼都做出来了那个挺难的吧
点赞 评论 收藏
分享
预计下个星期就能开奖吧,哪位老哥来给个准信
华孝子爱信等:对接人上周说的是这周
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务