[CSP-S模拟测试110]题解
也许是最后一篇了。
A.最大或
不错的签到题。
对于二进制位来说,高位的一个1比低位的所有1的贡献总和还要大。
显然,$r$必选,因为$r$中所有1的相对考前。那么考虑如何构造另一个数。
首先$l$和$r$前几位相同的部分肯定是不能动的,所以从$l,r$不同那位开始贪心即可。如果$r$这位为0,只要构造的这个数爆不了$r$就让它的这位为1。
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> using namespace std; typedef long long ll; int T; ll l,r; void work() { scanf("%lld%lld",&l,&r); ll res=0;bool ok=0; for(int i=62;i>=0;i--) { int now=(r>>i)&1LL,nowl=(l>>i)&1LL; if(now!=nowl)ok=1; //cout<<i<<' '<<now<<' '<<nowl<<' '<<ok<<endl; if(!now) if((res|(1LL<<i))<=r&&ok)res|=1LL<<i; } printf("%lld\n",r|res); } int main() { freopen("maxor.in","r",stdin); freopen("maxor.out","w",stdout); scanf("%d",&T); while(T--)work(); return 0; }
B.答题
题意可以转化为:求用所给的$n$个数组成的$2^n$个数中的第$k$大值,$k=ceil(2^n \times p)$。
然后就是裸的折半搜索了。分别搜出前一半和后一半的子集和,然后二分答案。
之后考虑如何求 从两组数里各取一个数,且令取出的两数和$\ge$二分值的数对的个数。
先把两组数排序,然后枚举第一组选到哪个,第二组维护一个倒着扫的单调指针即可。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int n,a[45],n1,n2,sz1,sz2; double p; ll kth; vector<int>s1,s2; void dfs(int x,int tot,int op) { if(!op&&x>n1) { s1.push_back(tot); return ; } if(op&&x>n) { s2.push_back(tot); return ; } dfs(x+1,tot,op); dfs(x+1,tot+a[x],op); } bool check(int val) { ll res=0;int j=sz2; for(int i=0;i<sz1;i++) { res+=sz2-j; while(j>0&&s2[j-1]+s1[i]>=val)j--,res++; } return res>=kth; } #define F int main() { #ifdef F freopen("answer.in","r",stdin); freopen("answer.out","w",stdout); #endif scanf("%d%lf",&n,&p); for(int i=1;i<=n;i++) scanf("%d",&a[i]); kth=(1LL<<n)-ceil(1.0*(1LL<<n)*p)+1; n1=n/2; dfs(1,0,0);dfs(n1+1,0,1); sz1=s1.size();sz2=s2.size(); sort(s1.begin(),s1.end()); sort(s2.begin(),s2.end()); int l=0,r=1e9,ans; while(l<=r) { int mid=l+r>>1; if(check(mid))ans=mid,l=mid+1; else r=mid-1; } cout<<ans<<endl; return 0; }
C.联合权值·改
其实正解挺神的……但是它w范围这么小 不用白不用啊。
直接开桶维护每个联合权值的个数,然后利用bitset去除三元环的情况即可。
我没脸
#include<cstdio> #include<iostream> #include<cstring> #include<bitset> using namespace std; #define pa pair<int,int> #define re register inline int read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } typedef long long ll; const int N=3e4+5; int n,m,t; int to[N<<1],head[N],nxt[N<<1],tot,ansm; pa p[N<<1]; bitset<N> s[N]; ll w[N],anss,bu[N>>1],cnt[N>>1]; inline void add(re int x,re int y) { to[++tot]=y; nxt[tot]=head[x]; head[x]=tot; } inline void print() { if(t!=2)printf("%d\n",ansm); else puts("0"); if(t!=1)printf("%lld\n",anss); else puts("0"); } #define F int main() { #ifdef F freopen("link.in","r",stdin); freopen("link.out","w",stdout); #endif n=read();m=read();t=read(); for(re int i=1;i<=m;i++) { int x=read(),y=read(); p[i]=make_pair(x,y); add(x,y);add(y,x);s[x][y]=1;s[y][x]=1; } for(re int i=1;i<=n;i++) w[i]=read(); for(re int x=1;x<=n;x++) { memset(bu,0,sizeof(bu)); for(re int i=head[x];i;i=nxt[i]) { int y=to[i]; for(int k=1;k<=100;k++) cnt[w[y]*k]+=bu[k]; bu[w[y]]++; } } for(int i=1;i<=m;i++) { int now=(s[p[i].first]&s[p[i].second]).count();//cout<<i<<' '<<now<<endl; cnt[w[p[i].first]*w[p[i].second]]-=now; } for(int i=1;i<=10000;i++) anss+=1LL*i*cnt[i],ansm=max(ansm,cnt[i]?i:0); anss*=2; print(); return 0; }
兴许青竹早凋,碧梧已僵,人事本难防。