This is a 玄学 exam
A.年轮蛋糕
最小的最大,二分首选
断环为链,check(x),x为答案,然后将每个大于x的子区间记录下来
如果有大于3个的话,那么x就可以是答案
那么·,在优化下来,二分里套个下二分,查长度右端点
时间复杂度:O(log(10^13)^3*n)
但是AC了
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } long long n,a[300001],s[300001],l,r,mid,maxn,inf=2<<30-1; long long cx(long long ll,long long rr,long long sc) { long long da=inf; long long ls=ll,rs=rr,mid; while(ls<=rs) { mid=(ls+rs)/2; if(s[mid]>=sc) da=min(da,mid),rs=mid-1; else ls=mid+1; } return da; } bool check(long long xx) { for(long long i=1;i<=n;i++) { long long qv=s[i-1],ll=i,rr=i+n-1,res=0; while(ll<=rr) { if(res==2) { if(s[rr]-qv>=xx) return 1; else break; } long long as=cx(ll,rr,qv+xx); if(as==inf) { if(res>=3) return 1; else break; } qv=s[as]; ll=as+1; res++; if(res==2) { if(s[rr]-qv>=xx) return 1; else break; } if(res>=3) return 1; } } return 0; } int main() { n=read(); for(long long i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i],r+=a[i]; for(long long i=1;i<=2*n;i++) s[i]=s[i-1]+a[i]; while(l<=r) { mid=(l+r)/2; if(check(mid)) maxn=max(maxn,mid),l=mid+1; else r=mid-1; } printf("%lld",maxn); }
B.最佳团体
玄学题目
复杂度未知,假装是A了吧
一看到一个和/一个和,分数规划的经典题
又想到若x可以作为答案的话,x之前也可以作为答案
所以可以二分
然后这个问题可以转化成在树上做背包即可
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } double eps=1e-4; struct node{ int u,v,nex; }x[2503]; int cnt,n,head[2503],s[2503],t[2503]; double val[2503],dp[2503][2503]; double l,r,mid,maxn; void add(int u,int v) { x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++; } int m,size[5001],deep[5001]; void dfs(int f,int fath) { deep[f]=deep[fath]+1; size[f]=1; for(int i=head[f];i!=-1;i=x[i].nex) { dfs(x[i].v,f); size[f]+=size[x[i].v]; } } void dp_tree(int xx) { dp[xx][0]=0;int k=min(m,size[xx]); for(int i=head[xx];i!=-1;i=x[i].nex) { int v=x[i].v; dp_tree(v); for(int t=k;t>=0;t--) for(int j=min(t,size[v]);j>=1;j--) dp[xx][t]=max(dp[xx][t],dp[xx][t-j]+dp[v][j]); } if(xx!=0) for(int t=k;t>=1;t--) dp[xx][t]=dp[xx][t-1]+val[xx]; } bool check(double xx) { bool flag=false; memset(dp,0xcf,sizeof(dp)); for(int i=1;i<=n;i++) val[i]=double(s[i]-xx*t[i]); dp_tree(0); return dp[0][m]>=0; } int main() { memset(head,-1,sizeof(head)); m=read(),n=read(); for(int i=1;i<=n;i++) { t[i]=read(),s[i]=read(); r+=double(s[i]); int v=read(); add(v,i); } dfs(0,0); l=0,r*=10; while(l<=r) { double mid=(l+r)/2; if(check(mid)) l=mid+eps,maxn=max(maxn,mid); else r=mid-eps; } printf("%.3lf",maxn); }
C.起床困难综合症
一道思维题,二进制运算至于位有关,并没有与整体有关
所以就可以打一个表,0000000,1111111,位数都为30为(int的精度),然后与输入数据处理一下
看一下0可以转换成什么,1可以转换成什么
然后瞎搞一下即可
#include<iostream> #include<cstdio> #include<cstring> #include<climits> #include<algorithm> using namespace std; inline int read() { int f=1,ans=0;char c; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();} return f*ans; } int n,m,l,r=INT_MAX,data,sry; char str[5]; int main() { n=read(),m=read(); for(int i=1;i<=n;i++) { scanf("%s",str+1); if(str[1]=='A') {int s=read();l&=s,r&=s;} else if(str[1]=='O') {int s=read();l|=s,r|=s;} else {int s=read();l^=s,r^=s;} } for(int i=30;i>=0;i--) { if(l&(1<<i)) data|=(1<<i); else if(sry+(1<<i)<=m) if(r&(1<<i)) data|=(1<<i),sry+=(1<<i); } cout<<data; } /* 3 10 AND 5 OR 6 XOR 7 */