2019-8-13 考试总结
A. count
在我看来不是个水题。。
想了好长时间,想到和正解差不多的思路,
本质应该是个贪心。
每次递归求每个节点的$size$,如果这个节点的$size$是现在枚举的每块的大小$L$,那么它的$size$置为$0$,
看一下到根节点的时候$size$是否为$0$。
思路应该是对的。
正解要好一点,看一下有多少节点的$size$可以整除$L$,如果这个数大于等于$\frac{n}{L}$,则$ans++$。
丑陋的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #define Reg register #define Maxn 1000050 using namespace std; int n,tot,ans,top,anp,now,siz[Maxn],fir[Maxn],vis[Maxn],num[Maxn]; struct Tu {int st,ed,next;} lian[Maxn*2]; void add(int x,int y) { lian[++tot].st=x; lian[tot].ed=y; lian[tot].next=fir[x]; fir[x]=tot; return; } void dfs(int x,int fa) { siz[x]=1; for(Reg int i=fir[x];i;i=lian[i].next) { if(lian[i].ed==fa) continue; dfs(lian[i].ed,x); siz[x]+=siz[lian[i].ed]; } ++num[siz[x]]; return; } int main() { scanf("%d",&n); for(Reg int i=1,x,y;i<=n-1;++i) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); for(Reg int i=n;i>=1;--i) { if(n%i!=0) continue; int p=0; for(Reg int j=1;i*j<=n;++j) p+=num[i*j]; if(p>=n/i) ++ans; } printf("%d",ans); return 0; }
B. Dinner
好吧,它是个圆桌。。
上来看完$T1$没啥思路然后滚来看$T2$,乍一看二分答案水题。。
结果我就$WA0$了。
还要枚举一个起点,暴力的话时间复杂度$O(n^2logn)$。
承受不住。
根据$starsing$大神的推导,只要枚举$1$号点可以一次到达的点即可。
因为如果把这个点之后的点当作起点,就相当于把它作为中间的断点,把$1$能到达的某个点当作起点,因为是个圆桌。
丑陋的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #define Maxn 50050 #define Reg register #define INF 0x7ffffff #define int long long #define _min(x,y) ((x)<(y)?(x):(y)) #define _max(x,y) ((x)>(y)?(x):(y)) #define _abs(x) ((x)<0?(-1*(x)):(x)) using namespace std; int n,m,mxx,mnn,T[Maxn*2],sum[Maxn*2],nxt[Maxn*2][20],vis[Maxn*2]; bool judge(int t) { int p=1; while(p+1<=2*n&&sum[p+1]-sum[1]<=t) ++p; for(Reg int s=1;s<=p;++s) { int p=0,now=s; for(Reg int i=1;i<=m;++i) now=upper_bound(sum+i,sum+n*2+1,sum[now]+t)-sum-1; if(now>=s+n) return 1; } return 0; } int erfen(int l,int r) { if(l==r) return l; int mid=(l+r)>>1; if(judge(mid)) return erfen(l,mid); else return erfen(mid+1,r); } signed main() { scanf("%lld%lld",&n,&m); for(Reg int i=1;i<=n;++i) { scanf("%lld",&T[i]); sum[i]=sum[i-1]+T[i]; mxx+=T[i]; mnn=_max(mnn,T[i]); } for(Reg int i=n+1;i<=n*2;++i) { T[i]=T[i-n]; sum[i]=sum[i-1]+T[i]; } if(m>=n) printf("%lld\n",mnn); else { int ans=erfen(mnn,mxx); printf("%lld\n",ans); } return 0; }
C. chess
总结:
怎么说呢,考试一次高一次低,起伏有点大。。
可能是我太菜了。。。
总体来说没上次考得好,主要是$T2$。
当时审题可能有问题,而且非常想当然,以为完全能过这道题。。
样例$2$: $4$ $2$ $1$ $2$ $3$ $4$。
输出: $5$
样例$2$错误解释:
把第三个人分开,分成一个$1$和一个$2$。
然后左边就成了$1+2+2=5$,右边也是$1+4=5$。
正确解释:
从第二个人开始,然后$2+3=5$,$4+1=5$。
审题仔细,不要想当然。
心态的话,应该还不错。
最后$60+0+30=90$。
没什么水平。。。