20190914

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\n",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\n",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\n",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\n",sum);
}
} signed main() {Luitaryi::main(); return 0;}

B3 40pts

咕?

仍然B组比A组难???其实这回差不多

就我一个该做A组的因为降智而做了B组。。。神仙都去水A组了
OTZ L队A组280pts

posted @ 2019-09-16 23:27  LuitaryiJack  阅读(267)  评论(3编辑  收藏  举报