牛客练习赛20(ABC)

A. 礼物

题意:

我从买奥利奥的事情中想出了一个算法题:假设某个店铺有N种不同类型的1元奥利奥和M种不同类型的2元奥利奥,而且余量无限,我的钱有k元,我想把k元都用来买奥利奥,且可以买同类型的奥利奥,你能帮我算出有多少种购买方式吗?设答案为Z,这个数字也许会很大,所以我们只需要输出Z mod P的值。

分析:

计数问题,可以考虑动态规划:每个物品可以选无数次,即无穷背包,注意无穷背包的递推写法。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int N,M,K,P;
int d[MAXN];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--) {
        memset(d,0,sizeof(d));
        scanf("%d%d%d%d",&N,&M,&K,&P);
        d[0] = 1;
        for(int i = 1; i <= N; i++) {
            for(int k = 1; k <= K; k++)
                d[k] = (d[k] + d[k-1])%P;
        }
        for(int i = 1; i <= M; i++) {
            for(int k = 2; k <= K; k++)
                d[k] = (d[k] + d[k-2])%P;
        }
        printf("%d\n",d[K] );
    }
    return 0;
}
​

B. 麻婆豆腐

题意:

“咳咳...请听题!我手上有n枚硬币,第i枚正面朝上的概率是Pi。我现在每个硬币各抛一次,正面朝上看做1,背面朝上看做0,把所有硬币得到的数异或起来决定最后得到的数。问:有多少个子集合使得0和1的概率相等?” 不管音无给了怎样的数,奏都是一分钟不到就算出来了!不愧是前学生会长啊~ 于是他们就去食堂吃麻婆豆腐了,现在,你也来算一下吧。

分析:

可以说这个题很惊世骇俗了,当一个硬币的概率是0.5时,它一反转,所得异或值就会改变,而且概率相等,反之,当他的概率不是0.5时,概率必然不等,答案就转化为有多少个集合至少含有一个0.5的硬币,取补集,概率为0.5的硬币是

 
int main() {
    int T; scanf("%d",&T);
    for(int i = 0; i < T; i++) {
        int n;  scanf("%d",&n);
        int cnt = 0;
        double p;
        for(int i = 0; i < n; i++) {
            scanf("%lf",&p);
            if(p==0.5) cnt++;
        }
        cnt = n - cnt;
        long long ans = 1,cnts=1;
        for(int i = 0; i < n; i++)
            ans<<=1;
        for(int i = 0; i < cnt; i++)
            cnts<<=1;
        cout<<ans-cnts<<endl;
​
    }
    return 0;
}

C. 寻宝

题意:

这个迷宫由n个房间组成,编号为0到n - 1,每个房间里都有一颗宝石,房间通过单向通道连接。每个房间里有两个门:一个通向第R个房间(R=(a·v2 + b·v + c) mod n),另一个通向迷宫出口,一旦离开迷宫,便会触发自毁机关,将再也没有机会继续收集宝石。现在,她可以在任何地点进入迷宫,沿隧道移动并收集宝石。

分析:

因为每个点,出度均为1,点的数目 ,时间复杂度需要

那么图里面只有环,和链+环,这样标记遍历即可。

首先遍历链,发现有环后,从那里再第二次标记,这样,环上每个结点都是环的长度。

链就相应要短一些。注意,访问的时候,下面的节点已经访问过了。

#include <bits/stdc++.h>
 
using namespace std;
 
long long a,b,c,m;
 
long long f(long long v) {
    return (a*v*v + b*v + c)%m;
}
 
int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    scanf("%d",&T);
 
    while(T--) {
 
        scanf("%lld%lld%lld%lld",&a,&b,&c,&m);
        vector<long long> L(m,-1);
 
        for(long long i = 0; i < m; i++) {
            if(L[i]>=0) continue;
 
            long long p = i;
            long long plen = 0;
 
            while(L[p]==-1) {
                L[p] = -2;
                plen ++;
                p = f(p);
            }
 
            if(L[p]>0) {
                plen+=L[p];
            }
 
            long long clen = 0;
            while(L[p]==-2) {
                L[p] = -3;
                clen++;
                p = f(p);
            }
 
            p = i;
            while(L[p]<0) {
                if(L[p]==-3) L[p] = clen;
                if(L[p]==-2) L[p] = plen--;
                p = f(p);
            }
        }
        cout<<*max_element(L.begin(),L.end())<<endl;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/TreeDream/p/9318472.html