测试「20201028测试总结」
教练终于考NOIP模拟题了。
T1
真 · 签到题,直接使用math库函数即可。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long lxl;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,m;
int main()
{
#ifndef ONLINE_JUDGE
freopen("check.in","r",stdin);
freopen("check.out","w",stdout);
#endif
read(n),read(m);
long double ans=exp(log((long double)n)/(long double)m);
printf("%d\n",(int)ans);
return 0;
}
T2
先只考虑除了 \(2\) 以外的质数,发现只有偶数和奇数之间连边,也就是一个二分图,可以只用两种颜色。
考虑 \(2\) 其实是将偶数和奇数分别连成一条链,我们让链上的颜色交替出现即可。
发现这样最多只有 \(4\) 种颜色,\(n\) 比较小的时候打表即可。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long lxl;
const int maxn=1e4+5;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
int n,color[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
#endif
read(n);
if(n==1) return puts("1\n1"),0;
if(n==2) return puts("1\n1 1"),0;
if(n==3) return puts("2\n1 1 2"),0;
if(n==4) return puts("2\n1 1 2 2"),0;
if(n==5) return puts("3\n2 1 1 3 2"),0;
for(int i=1,type=0;i<=n;i+=2,type^=1)
color[i]=1+type;
for(int i=2,type=0;i<=n;i+=2,type^=1)
color[i]=3+type;
puts("4");
for(int i=1;i<=n;++i)
printf("%d ",color[i]);
return 0;
}
T3
没怎么看懂,想找出题人对线,但是找不到出题人/kk。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long lxl;
const int maxn=2e5+5;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
lxl n,m,k,a[maxn];
lxl D;
int main()
{
#ifndef ONLINE_JUDGE
freopen("array.in","r",stdin);
freopen("array.out","w",stdout);
#endif
int T;read(T);
while(T--)
{
read(n),read(m),read(k),read(D);
lxl sum=0;
for(int i=1;i<=m;++i) read(a[i]),sum+=a[i];
sort(a+1,a+m+1);
lxl ans=0;
for(int i=1;i<=m;++i)
{
lxl Min=min(n,D/sum);
ans=max(ans,n*(i-1)+Min*(m-i+1)+min(n-Min,(D-sum*Min)/a[i])+Min*k);
if(D<a[i]*n)
{
ans=max(ans,D/a[i]+n*(i-1));
break;
}
if(i!=m)
{
lxl tmp=(D-a[i]*n)/(sum-a[i])+1;
if(D>=tmp*sum)
printf("%lld %lld\n",tmp+min(n-tmp,(D-tmp*sum)/a[i]),tmp),
ans=max(ans,n*(i-1)+tmp*(m-i+1)+min(n-tmp,(D-tmp*sum)/a[i])+tmp*k);
}
sum-=a[i];
D-=a[i]*n;
}
printf("%lld\n",ans);
}
return 0;
}
T4
其实就是求树上路径上点 \(x\) 满足:
\[dis(l,x)=x
\]
的个数。
分成 \(l\to LCA\) 和 \(LCA\to r\) 两部分考虑。将式子拆开,得到:
\[\begin{aligned}
dep_l-dep_x=x&\implies dep_l=x+dep_x\\
dep_l+dep_x-2\times dep_{LCA}=x&\implies dep_l-2\times dep_{LCA}=x-dep_x
\end{aligned}
\]
树上差分即可求出答案。
\(\text{Code}:\)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <vector>
using namespace std;
typedef long long lxl;
const int maxn=3e5+5;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x)
{
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
x*=f;
}
struct edge
{
int u,v,next;
edge(int u,int v,int next):u(u),v(v),next(next){}
edge(){}
}e[maxn<<1];
int head[maxn],ecnt;
inline void add(int u,int v)
{
e[ecnt]=edge(u,v,head[u]);
head[u]=ecnt++;
}
int n,m;
namespace Tree
{
int dep[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn];
void dfs1(int u)
{
dep[u]=dep[fa[u]]+1;
siz[u]=1;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==fa[u]) continue;
fa[v]=u;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
void dfs2(int u,int t)
{
top[u]=t;
if(!son[u]) return;
dfs2(son[u],t);
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
inline int LCA(int a,int b)
{
for(;top[a]!=top[b];dep[top[a]]>dep[top[b]]?a=fa[top[a]]:b=fa[top[b]]);
return dep[a]<dep[b]?a:b;
}
}
struct ques // 询问从根到这个点的路径上有多少点 dep_i+i==val 或者 i-dep_i==val
{
int val,id,type;
ques(int val,int id,int type):val(val),id(id),type(type){}
ques(){}
};
pair<int,int> querys[maxn];
vector<ques> Q[maxn];
vector<ques>::iterator it;
int ans[maxn];
int val[maxn];
int sum[maxn<<1];
void dfs(int u)
{
++sum[val[u]];
for(it=Q[u].begin();it!=Q[u].end();++it)
ans[it->id]+=it->type*sum[it->val];
Q[u].clear();
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(v==Tree::fa[u]) continue;
dfs(v);
}
--sum[val[u]];
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("query.in","r",stdin);
freopen("query.out","w",stdout);
#endif
read(n),read(m);
memset(head,-1,sizeof(head));
for(int i=1,u,v;i<n;++i)
{
read(u),read(v);
add(u,v);add(v,u);
}
Tree::dfs1(1);
Tree::dfs2(1,1);
for(int i=1,l,r;i<=m;++i)
{
read(l),read(r);
querys[i]=make_pair(l,r);
}
for(int i=1;i<=n;++i)
val[i]=i+Tree::dep[i];
for(int i=1;i<=m;++i)
{
int u=querys[i].first,v=querys[i].second;
int f=Tree::LCA(u,v);
Q[u].push_back(ques(Tree::dep[u],i,1));
if(Tree::fa[f]) Q[Tree::fa[f]].push_back(ques(Tree::dep[u],i,-1));
}
dfs(1);
for(int i=1;i<=n;++i)
val[i]=i-Tree::dep[i]+n;
for(int i=1;i<=m;++i)
{
int u=querys[i].first,v=querys[i].second;
int f=Tree::LCA(u,v);
Q[v].push_back(ques(Tree::dep[u]-2*Tree::dep[f]+n,i,1));
Q[f].push_back(ques(Tree::dep[u]-2*Tree::dep[f]+n,i,-1));
}
dfs(1);
for(int i=1;i<=m;++i)
printf("%d\n",ans[i]);
return 0;
}