NOIP2015
提高组
day1
T1
纯模拟。
T2
Description
给定一个有向图,求最小的环的大小。
Solution
因为每个点的出度都为1,没有自环,所以直接tarjan求每个环的大小即可。
#include<bits/stdc++.h>
using namespace std;
const int N=200005;
struct graph{
int nxt,to;
}e[N];
int g[N],f[N],dfn[N],low[N],sta[N],n,top,ans,cnt;
bool ins[N];
void tarjan(int u){
dfn[u]=low[u]=++cnt;
sta[++top]=u;ins[u]=true;
for(int i=g[u];i;i=e[i].nxt)
if(!dfn[e[i].to]){
tarjan(e[i].to);
low[u]=min(low[u],low[e[i].to]);
}
else if(ins[e[i].to])
low[u]=min(low[u],low[e[i].to]);
if(dfn[u]==low[u]){
int tmp=0;
while(sta[top+1]!=u){
++tmp;
f[sta[top]]=u;
ins[sta[top--]]=false;
}
if(tmp>1) ans=min(ans,tmp);
}
}
void adde(int x,int y){
e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
}
int main(){
scanf("%d",&n);
for(int i=1,x;i<=n;++i){
scanf("%d",&x);
adde(i,x);
}
ans=n;cnt=0;
for(int i=1;i<=n;i++)
if(!dfn[i]) tarjan(i);
printf("%d",ans);
return 0;
}
day2
T1
Description
从一个数组中删去至多m个数,使\(min\{a_i-a_{i-1}\}\)最大。
Solution
二分答案,贪心判定。
#include<bits/stdc++.h>
using namespace std;
const int N=50005;
int d[N],n,m,l;
bool chk(int ans){
int cnt=0,lst_d=0;
for(int i=1;i<=n;++i){
if(d[i]-lst_d<ans) ++cnt;
else lst_d=d[i];
}
return cnt<=m;
}
int main(){
scanf("%d%d%d",&l,&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&d[i]);
d[++n]=l;
int lef=0,rig=l,mid;
while(lef<rig){
mid=(lef+rig+1)>>1;
if(chk(mid)) lef=mid;
else rig=mid-1;
}
printf("%d",lef);
return 0;
}
T2
T3
普及组
T3
条件1等价于x+z=2y,即x,z同奇偶。
问题转化成给定一个大小为\(n_c\)的集,求\(\sum_{x}\sum_{z,x<z}(x+z)\times(number_x+number_z)\).
\(\begin{aligned}&\sum_{x}\sum_{z,x<z}(x+z)\times(number_x+number_z)\\=&\sum_{x}\sum_{z,x<z}(x\times number_x+z\times number_z+x\times number_z+z\times number_x)\\=&\sum_{x}(n_c-1)(x\times number_x)+\sum_{x}\sum_{z,x\neq z}x\times number_z\\=&\sum_{x}(n_c-1)(x\times number_x)+\sum_{x}x\times \sum_{z,x\neq z}number_z\end{aligned}\)
预处理后扫一遍可求得。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=100005,K=10007;
int c[N],num[N],n,m;
int c1[N],c2[N];
ll ans,t1[N],t2[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&num[i]);
for(int i=1;i<=n;++i)
scanf("%d",&c[i]);
for(int i=1;i<=n;++i)
if(i&1){
++c1[c[i]];
t1[c[i]]+=num[i];
}
else{
++c2[c[i]];
t2[c[i]]+=num[i];
}
for(int i=1;i<=m;++i){
c1[i]%=K;c2[i]%=K;
}
for(int i=1;i<=n;++i)
if(i&1){
ans+=1ll*i*num[i]%K*(c1[c[i]]-1)%K;
ans%=K;
}
else{
ans+=1ll*i*num[i]%K*(c2[c[i]]-1)%K;
ans%=K;
}
for(int i=1;i<=n;++i)
if(i&1){
ans+=1ll*i*(t1[c[i]]-num[i])%K;
ans%=K;
}
else{
ans+=1ll*i*(t2[c[i]]-num[i])%K;
ans%=K;
}
printf("%lld\n",ans);
return 0;
}
T4
用线段树贪心即可。
#include<bits/stdc++.h>
using namespace std;
const int N=100005,M=400005;
struct segmentTree{
int ma,mw,ia,iw;
}lt[M];
int a[N],s[N],n,max_s,ans;
void build(int u,int l,int r){
if(l==r){
lt[u].ma=a[l];
lt[u].mw=a[l]+s[l]*2;
lt[u].ia=lt[u].iw=l;
return;
}
int mid=(l+r)>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
if(lt[u<<1].ma>lt[u<<1|1].ma){
lt[u].ma=lt[u<<1].ma;
lt[u].ia=lt[u<<1].ia;
}
else{
lt[u].ma=lt[u<<1|1].ma;
lt[u].ia=lt[u<<1|1].ia;
}
if(lt[u<<1].mw>lt[u<<1|1].mw){
lt[u].mw=lt[u<<1].mw;
lt[u].iw=lt[u<<1].iw;
}
else{
lt[u].mw=lt[u<<1|1].mw;
lt[u].iw=lt[u<<1|1].iw;
}
}
int ask(int u,int l,int r,int &i){
if(l==r){
i=l;
if(s[l]<=max_s) return lt[u].ma;
return lt[u].mw-max_s*2;
}
if(s[l]>=max_s){
i=lt[u].iw;
return lt[u].mw-max_s*2;
}
if(s[r]<=max_s){
i=lt[u].ia;
return lt[u].ma;
}
int mid=(l+r)>>1;
if(s[mid+1]>=max_s){
int ret_l=ask(u<<1,l,mid,i);
int ret_r=lt[u<<1|1].mw-max_s*2;
if(ret_l>ret_r) return ret_l;
i=lt[u<<1|1].iw;
return ret_r;
}
int ret_l=lt[u<<1].ma;
int ret_r=ask(u<<1|1,mid+1,r,i);
if(ret_l>ret_r){
i=lt[u<<1].ia;
return ret_l;
}
return ret_r;
}
void remove(int u,int l,int r,int i){
if(l==r){
lt[u].ma=0;lt[u].mw=0;
return;
}
int mid=(l+r)>>1;
if(i<=mid) remove(u<<1,l,mid,i);
else remove(u<<1|1,mid+1,r,i);
if(lt[u<<1].ma>lt[u<<1|1].ma){
lt[u].ma=lt[u<<1].ma;
lt[u].ia=lt[u<<1].ia;
}
else{
lt[u].ma=lt[u<<1|1].ma;
lt[u].ia=lt[u<<1|1].ia;
}
if(lt[u<<1].mw>lt[u<<1|1].mw){
lt[u].mw=lt[u<<1].mw;
lt[u].iw=lt[u<<1].iw;
}
else{
lt[u].mw=lt[u<<1|1].mw;
lt[u].iw=lt[u<<1|1].iw;
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&s[i]);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]);
build(1,1,n);
int ans_i;
for(int i=1;i<=n;++i){
ans+=ask(1,1,n,ans_i);
max_s=max(max_s,s[ans_i]);
remove(1,1,n,ans_i);
printf("%d\n",ans);
}
return 0;
}