赛时 AC 题目
点击查看代码
/*
1. 根据山峰数列的定义,用排列组合知识去计算即可。
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
int t,n;
int a[maxn];
ll ans;
const int MOD=998244353;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
ans=1ll;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
int e=n;
while(a[e]==a[n]) e--;
int cnt=0,s=0;
for(int i=1;i<=e;i++)
{
if(a[s]!=a[i])
{
ans=(cnt+1)*ans%MOD;
s=i,cnt=1;
}
else cnt++;
}
ans=(cnt+1)*ans%MOD;
printf("%lld\n",ans);
}
}
点击查看代码
/*
1. 模拟+贪心的水题。
*/
#include<bits/stdc++.h>
using namespace std;
int t,l,r,cnt;
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&l,&r,&cnt);
int pos;
while(cnt&&l<=r)
{
pos=(l+r)>>1;
if(r-pos>pos-l) l=pos+1;
else r=pos-1;
cnt--;
}
if(cnt) printf("-1\n");
else printf("%d\n",pos);
}
return 0;
}
点击查看代码
/*
1. 突破点在于发现,$\max\limits_{i\ne j}\{|\frac{a_i-a_j}{i-j}|\}$ 一定在当 $j=i+1$ 时取到(可以用**反证法**证明),故只需计算相邻元素的差的最大值。
2. 对于 $a$ 的差分数组 $d$,要求满足**单点修改**和**求区间最大值**的操作。本题中,由于区间一直是 $[2,n]$,故可直接用 $L$ 维护区间最大值,然后每次修改 $d$ 数组时,更新 $L$。
3. 代码中用了线段树,是因为当时没有注意到区间一直是 $[2,n]$(nt 了)。
*/
#include<bits/stdc++.h>
#define ld long double
#define lson i<<1
#define rson i<<1|1
using namespace std;
const int maxn=5e5+100;
int n,q,a[maxn];
struct ST
{
int mx,mi;
}t[maxn<<2];
void build(int i,int L,int R)
{
if(L==R)
{
t[i].mx=t[i].mi=a[R+1]-a[R];
return;
}
int mid=(L+R)>>1;
build(i<<1,L,mid),build(i<<1|1,mid+1,R);
t[i].mx=max(t[i<<1].mx,t[i<<1|1].mx);
t[i].mi=min(t[i<<1].mi,t[i<<1|1].mi);
return;
}
void merge(int i,int l,int r,int pos,int k)
{
if(l==r&&l==pos)
{
t[i].mx+=k,t[i].mi+=k;
return;
}
int mid=(l+r)>>1;
if(pos<=mid) merge(lson,l,mid,pos,k);
else merge(rson,mid+1,r,pos,k);
t[i].mx=max(t[i<<1].mx,t[i<<1|1].mx);
t[i].mi=min(t[i<<1].mi,t[i<<1|1].mi);
return;
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n-1);
printf("%lf\n",1.0*max(abs(t[1].mx),abs(t[1].mi)));
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
if(l-1)merge(1,1,n-1,l-1,k);
if(r<n)merge(1,1,n-1,r,-k);
printf("%lf\n",1.0*max(abs(t[1].mx),abs(t[1].mi)));
}
return 0;
}
赛事未 AC 的题目(补)
点击查看代码
/*
1. 用 dfs 求出 dfn,其中 dfn 是 dfs 搜索树时第一次遇到节点的次序。
2. 可以发现,一个节点 u 及其子树的 dfn 序为一个连续的区间 [dfn[u],dfn[u]+size[u]-1]。
3. 本题便可做了,详细操作见代码。
*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+5;
int n,m,q;
struct edge
{
int v,next;
} e[maxn<<1];
int head[maxn],sz[maxn],cnt,tot;
void add(int u,int v)
{
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int dfn[maxn];
void Init_dfn(int u,int fa)
{
dfn[u]=++tot;int v;sz[u]=1;
for(int i=head[u];i;i=e[i].next)
{
v=e[i].v;
if(v==fa) continue;
Init_dfn(v,u);
sz[u]+=sz[v];
}
}
struct ST
{
int t[maxn];
ST(){memset(t,0,sizeof(t));}
void fadd(int x,int k)
{
for(int i=x;i<=n;i+=(i&-i))
t[i]+=k;
}
int ask(int x)
{
int ans=0;
for(int i=x;i;i-=(i&-i))
ans+=t[i];
return ans;
}
} T;
vector<int> go_to[maxn],b[maxn];
int ans[maxn],ed[maxn];
void solve(int u,int fa)
{
vector<int>::iterator it=go_to[u].begin();
int v,idx;
for(it;it!=go_to[u].end();it++)
//cout<<u<< " " <<*it<<"?"<<endl,
T.fadd(dfn[*it],1);
for(it=b[u].begin();it!=b[u].end();it++)
{
idx=*it,v=ed[idx];
ans[idx]=T.ask(dfn[v]+sz[v]-1)-T.ask(dfn[v]-1);
//cout<<T.ask(1);
}
for(int i=head[u];i;i=e[i].next)
{
v=e[i].v;
if(v==fa) continue;
solve(v,u);
}
for(it=go_to[u].begin();it!=go_to[u].end();it++)
T.fadd(dfn[*it],-1);
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
int u,v;
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u,&v);
add(u,v),add(v,u);
}
Init_dfn(1,0);
/*
for(int i=1;i<=n;i++)
cout<<dfn[i]<<" ";
cout<<endl;
*/
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
go_to[u].push_back(v);
}
for(int i=1;i<=q;i++)
{
scanf("%d%d",&u,&v);
ed[i]=v,b[u].push_back(i);
}
solve(1,0);
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}