牛客练习赛20(ABC)
题意:
我从买奥利奥的事情中想出了一个算法题:假设某个店铺有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; }