T1:akinator
这题很简单,但是有三个方法:
1.二叉树法
将它的询问想象成一棵二叉树,'Y'就向左,'N'就向右,我们都知道二叉树的左子树为2*n,右子树为2*n+1,那我们定义一个变量x,遇到'Y',就*2,遇到'N',就*2+1,最后再减去[pow(2*n)-1]即可,因为得到的结论是叶子节点,且是按(1,2,3,4,5,6......)排的,所以要减去上面多算的那颗完美二叉树也就是[pow(2*n)-1]。
2.进制法
我们可以发现,如果我们将'Y'设为0,'N'设为1,则每一串问题我们都可以用一串二进制编码来表示,我们再将二进制编码,转十进制即可。
3.二分法
我们可以发现,它的询问是一棵二叉树的话('Y'设为0,'N'设为1)则得到一个回答,就可以排除一半的答案(选了右子树,排除左子树;选了左子树,排除右子树)。且我们要求的结论满足单调性,所以可以考虑二分。
T2:prim
这题还好(1秒的情况就不好了)
考验的是筛法,主要考察的是数学,筛法,快速幂(不会也可以手打pow),上一次我不知是为何是一个50分(10月4日)但这次对了,回到正题:
本题思路
一看题目标题,就看到了质数,我们就想到了埃氏筛(O(n log log n)),主要是不会欧拉筛(O(n)),本题给了2s够了不会超时。然后我们看题,发现答案只与质数和一有关,则我们将质数和1的个数分别用cnt和res存起来。我们又发现可以1和任何质数搭配且根据乘法原理(每个1都有两种选择:选或不选)那么公式就是pow(res)*cnt;
注意事项:
1.一定要取余(mod=1e9+7)。
2.一定要手打(pow函数);
T3:candy
这题分糖果(又是那种暴力简单,正解困难的题)
暴力就是枚举两个数然后将他们%m再取max;
正解(排序+二分):
1.我们可以提前先将它们与m取余
2.我们取余之后,再排序
3.现在有了单调性,我们再枚举一个数,二分另一个数,使他们的和为不超过m的最大的数(若和>=m 往小的移动否则往大的移动)
4.ans在二分结束后取max
5.ans在最后要与(a[n]+a[n-1])%m(比m多的最大的数)取max
6.切记一定一定一定要初始化
代码放一下:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+88;
long long n,T,a[N],m,ans=0;
bool vis[N];
void work(){
ans=-1e9;
cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> a[i];
a[i]%=m;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
// cout<<"i="<<i<<endl;
int l=i,r=n+1;
while(l+1<r){
// cout<<l<<' '<<r<<endl;
int mid=(l+r)>>1;
long long x=a[i]+a[mid];
// cout<<x<<endl;
if(x/m == 0){
l=mid;
}else{
r=mid;
}
}
// cout<<"l="<<l<<endl;
if(l!=i) ans=max(ans,(a[i]+a[l])%m);
}
ans=max(ans,(a[n]+a[n-1])%m);
cout << ans << endl;
}
int main(){
freopen("candy.in","r",stdin);
freopen("candy.out","w",stdout);
cin >> T;
while(T--){
work();
}
return 0;
}