A1
先贪心的(可能你们觉得很显然),我们直接从前往后扫,并且让每个区间尽量长。
如何判断?差的 gcd 不为 1 + map 判重复元素。
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=100010;
int n,a[N],ans;
unordered_map<int,int> vis;
inline void main() {
n=g(); for(R i=1;i<=n;++i) a[i]=g(); R p=0,d=0,lst=1;
while(p<=n) {
vis.clear(),vis[a[lst]]=true,p=lst+1,d=abs(a[lst]-a[lst+1]);
while(p<=n&&!vis[a[p]]&&(d=__gcd(d,abs(a[p]-a[p-1])))!=1)
vis[a[p]]=true,++p; ++ans; lst=p;
} printf("%d
",ans);
}
} signed main() {Luitaryi::main(); return 0;}
A2
WAI L队 又双叒叕暴力水标算(虽然被Hack了)
其实 L队 的思路还挺好的,有向边表示包含关系(想不到啊。。我好菜啊)
正解是离线建树,并存下每个点往上的两种极长链,然后用dfs序判断是否包含。
这样当极长链的长度大于等于两个点的距离时才能保证关系。
#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0;
register char ch; while(!isdigit(ch=getchar()));
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x;
} const int M=2e6+10,N=2.5e5+10;
struct node {int u,v;}a[N]; int cnt,n,m,num,tot;
int vr[M],nxt[M],fir[N<<1],f[N<<1][2],d[N<<1],c[N<<1],dfn[N<<1],low[N<<1],ind[N<<1];
inline void add(int u,int v) {vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;}
inline void dfs(int u) { dfn[u]=++num;
for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
if(!c[u]||ind[u]==1) f[v][0]=f[u][0]+1; else f[v][0]=0;
if( c[u]||ind[u]==1) f[v][1]=f[u][1]+1; else f[v][1]=0;
d[v]=d[u]+1; dfs(v);
} low[u]=num;
}
inline void main() {
n=g(),m=g();
for(R i=1,op,lim;i<=m;++i) {
op=g(); if(!op) {
op=g(),lim=g(),++n,c[n]=op,ind[n]=lim;
for(R i=1,v;i<=lim;++i) v=g(),add(n,v);
} else a[++tot].u=g(),a[tot].v=g();
} for(R i=n;i;--i) if(!dfn[i]) dfs(i);
for(R i=1;i<=tot;++i) {
if(dfn[a[i].u]<=dfn[a[i].v]&&low[a[i].v]<=low[a[i].u])
if(f[a[i].v][0]>=d[a[i].v]-d[a[i].u]) puts("1"); else puts("0");
else if(dfn[a[i].v]<=dfn[a[i].u]&&low[a[i].u]<=low[a[i].v])
if(f[a[i].u][1]>=d[a[i].u]-d[a[i].v]) puts("1"); else puts("0");
else puts("0");
}
}
} signed main() {Luitaryi::main(); return 0;}
A3
DP + 堆优化
(f[i]=min(sum_{j=i-k}^i f[j] + max(b[j],s[i]-s[j])))
发现每个点在又收税转为路费就再也不会再变回去。
于是上两个堆,分别维护两种转移。
详见代码:
#include<bits/stdc++.h>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=500010;
struct node { int p; ll w; node() {}
node(int _p,ll _w) {p=_p,w=_w;}
inline bool operator < (const node& that) const {return w>that.w;}
}; int n,k,a[N],b[N];
priority_queue<node> p,q;
ll f[N],s[N];
inline void main() {
n=g(),k=g();
for(R i=1;i<=n;++i) a[i]=g(),s[i]=s[i-1]+a[i];
for(R i=0;i<n;++i) b[i]=g();
memset(f,0x7f,sizeof(ll)*(n+1)); f[0]=0;
p.push(node(0,b[0])); for(R i=1;i<=n;++i) {
while(p.size()&&p.top().p<i-k) p.pop();
while(q.size()&&q.top().p<i-k) q.pop();
while(p.size()&&p.top().w<f[p.top().p]-s[p.top().p]+s[i]) {
R pos=p.top().p; p.pop(); if(pos<i-k) continue;
q.push(node(pos,f[pos]-s[pos]));
}
while(p.size()&&p.top().p<i-k) p.pop();
if(p.size()) f[i]=min(f[i],p.top().w);
if(q.size()) f[i]=min(f[i],q.top().w+s[i]);
p.push(node(i,f[i]+b[i]));
} printf("%lld
",f[n]);
}
} signed main() {Luitaryi::main(); return 0;}
B1 100pts
怕不是智商题:直接按题意模拟,交换两列;最后就是求一下逆序对数。
include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=100010;
int n,m,a[N],c[N],ans;
inline void add(int p,int d) {for(;p<=n;p+=p&-p) c[p]+=d;}
inline int query(int p) { R ret=0;
for(;p;p-=p&-p) ret+=c[p]; return ret;
}
inline void main() {
n=g(),m=g(); for(R i=1;i<=n;++i) a[i]=i;
for(R i=1,x;i<=m;++i) x=g(),swap(a[x],a[x+1]);
for(R i=1;i<=n;++i) printf("%d ",a[i]); puts("");
for(R i=1;i<=n;++i) ans+=query(n)-query(a[i]),add(a[i],1);
printf("%d
",ans);
}
} signed main() {Luitaryi::main(); return 0;}
B2 70pts
出题人你就不能使点劲卡sort吗。。。我T的每个点都是1.0xx s。。。QwQ
就是求每种人的个数,发现上取整(跟哪所学校根本没关系)
1e7 sort 我以为稳了(后来想起来上回是2s)
于是我们有哈希表!!!(数据随机)
awsl
=。=
#include<iostream>
#include<cstdio>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline ll g() { register ll x=0,f=1;
register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=1e7+10,LIM=100,B=109,C=107;
ll c[N],vl[N],m,lst,sum;
int pos,n,t;
inline void hash(const ll& x) {
int p=x%N;
while(vl[p]!=x&&vl[p]) {
++p; if(p>=N) p=0;
} if(!vl[p]) vl[p]=x;
++c[p];
}
inline void main() {
n=g(),m=g(); const ll M=m;
for(R i=1,lim=n/100;i<=lim;++i) {
lst=g(); hash(lst+1);
for(R i=1;i<LIM;++i) hash((lst=(lst*B+C)%M)+1);
}
for(R i=0;i<N;++i) if(vl[i]) sum+=(c[i]+vl[i]-1)/vl[i]*vl[i];
printf("%lld
",sum);
}
} signed main() {Luitaryi::main(); return 0;}
B3 40pts
咕?
仍然B组比A组难???其实这回差不多
就我一个该做A组的因为降智而做了B组。。。神仙都去水A组了
OTZ L队A组280pts