首师大附中集训第四天综合测试
作者:互联网
综合测试
考试的前一天老师说今天的题比NOI稍微简单一些。
第一题,给你n,要你求。定义为其所有约数的异或和。.
这题还是比较简单的,直接数论分块,讨论那些为奇数就行了。
求前缀和的时候考虑相邻两个数(偶奇)的异或和为1.然后讨论一下情况就可以了。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
long long n;
long long ans=0;
long long get_sum(long long x){
if(x%2==1) return ((x+1)/2)%2;
else return x^((x/2)%2);
}
int main(){
//freopen("Xor.in","r",stdin);
//freopen("Xor.out","w",stdout);
scanf("%lld",&n);
long long l=1,r;
while(l<=n){
r=n/(n/l);
if((n/l)&1){
if(l==r) ans^=l;
else ans^=get_sum(r)^get_sum(l-1);
}
l=r+1;
}
printf("%lld",ans);
}
第二题:给定长度为n的序列,每次给出一个[l,r]和一个x。
对于每一个询问计算有多少个三元组满足。
这题我的做法貌似和其他人不太一样,我是直接考虑补集转化。然后把或操作就变成了与操作。
接着,对于每一个ai,将他的子集位置上的值加上1,开个前缀数组记录一下,那么一个位置上的值就记录了所有超集的个数。
对于每一次询问的x,我们考虑一个三元组与的值不为x但在x的位置上被计算的,直接枚举x的超集,容斥一下就可以了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,m;
int p[100010][256];
int a[100010];
long long C(long long x){
if(x<=2) return 0;
return 1ll*x*(x-1)*(x-2)/6;
}
long long dfs(int l,int r,int x,int now,int coef){
if(now==8) {
return C(p[r][x]-p[l-1][x])*coef;
}
long long tot=0;
tot+=dfs(l,r,x,now+1,coef);
if(!(x&(1<<now))) tot+=dfs(l,r,x|(1<<now),now+1,-coef);
return tot;
}
int main(){
//freopen("Or.in","r",stdin);
//freopen("Or.out","w",stdout);
scanf("%d %d",&n,&m);
int l,r,x;
for(int i=1;i<=n;i++) {
scanf("%d",&x);x^=255;
for(int j=0;j<=255;j++) {
p[i][j]=p[i-1][j];
if((x|j)==x) p[i][j]++;
}
}
while(m--){
scanf("%d %d %d",&l,&r,&x);x^=255;
printf("%lld\n",dfs(l,r,x,0,1));
}
}
第三题:从这题往后就没有正解了。
给出一张图,问存不存在两棵生成树没有重边。。
我的做法是直接暴力枚举边是否选(满足第一颗生成树的条件),然后在这个过程中check一下是否存在第二颗生成树。如果不存在就直接返回,因为到后面状态数就越多,所以这个剪枝在前面做就可以了,拿到了非比寻常的55分!
然而,有人直接每一次做很多次random_shuffle。然后从前往后做两遍最小生成树,就拿到了满分(我补题的时候写了这个东西连样例都过不了
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int T;
int n,m;
struct edge{
int x,y;
}s[110];
int fa[11],size[11],f[11];
bool tf[110],we=false;
int data=4;
int fp(int x){
if(f[x]!=x) return f[x]=fp(f[x]);
return x;
}
int findpa(int x){
if(fa[x]!=x) return findpa(fa[x]);
return x;
}
bool check(){
for(int i=1;i<=n;i++) f[i]=i;
int tot=0;
for(int i=1;i<=m;i++) if(!tf[i]){
int fx=fp(s[i].x),fy=fp(s[i].y);
if(fx!=fy) f[fx]=fy,tot++;
if(tot==n-1) return true;
}
return false;
}
bool dfs(int x,int now){
if(now==n && check()) return true;
if(x==m+1 || now==n) return false;
int fx=findpa(s[x].x),fy=findpa(s[x].y);
if(dfs(x+1,now)) return true;
if(fx!=fy){
if(size[fx]<size[fy]) swap(fx,fy);
fa[fy]=fx;size[fx]+=size[fy];tf[x]=true;
if((now>data || check()) && dfs(x+1,now+1)) return true;
size[fx]-=size[fy],fa[fy]=fy;tf[x]=false;
}
return false;
}
int main(){
//freopen("Game.in","r",stdin);
//freopen("Game.out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i,size[i]=1;
for(int i=1;i<=m;i++) scanf("%d %d",&s[i].x,&s[i].y),tf[i]=false;
printf(dfs(1,1)?"Possible\n":"Impossible\n");
}
}
第四题:啊这题真的亏,YY了一个决策单调性,结果最后5分钟hack了自己。
有两种二元组(x,y),对于两个二元组要你计算。其中1必须属于第一种二元组,2必须属于第二种二元组。
而且要求。问最大值。
我只会暴力。
听别人讲:把xy画在二维平面上,然后知道答案就相当于一个矩形的面积。
接着我们看一下第一类点,知道只有类似下凸壳上面的点才是有用的(这个下凸壳只要求x递增,y递减)。
第二类点,知道只有类似上凸壳上面的点才是有用的。(同理)
接着我们把两个序列random_shuffle5次,每次取前2000个点出来算一下点对。就可以拿到95的高分!
不用暴力,把相邻两个点的交界线算出来,然后相邻两条线算一下交点,就可以知道点在哪一块时可以获得最大价值,用set维护,可以拿到103的高分!
标签:师大附中,return,int,综合测试,long,fa,freopen,第四天,include 来源: https://blog.csdn.net/Deep_Kevin/article/details/97677199