前言
比赛时,只做出前3题,上了一点点分…(写得不好,请轻喷).
A Reachable Towns
有nnn个点,每个点有两个参数(xi,yi)(x_i,y_i)(xi,yi).
i,ji,ji,j有连边,当且仅当xi<xj,yi<yj or xi>xj,yi>yjx_i<x_j,y_i<y_j~~or~~x_i>x_j,y_i>y_jxi<xj,yi<yj or xi>xj,yi>yj.
求每个点的可达点数目.
显然这是一张无向图,我们数只要求连通块的大小即可.
我们先按xxx排序(使得xi=ix_i=ixi=i),然后对于每个点iii考虑连边.
如果存在j<i,yj<yij<i,y_j<y_ij<i,yj<yi那么i,ji,ji,j就在同一个连通块.
由此我们可以发现,我们只要记录一个连通块的最小yyy,用一个单调栈维护一下yyy单调下降即可.
并查集用按秩合并+路径压缩,可以总复杂度为O(nα(n))O(n\alpha(n))O(nα(n)).
int x[N],y[N],n,sta[N],top,fa[N],sz[N],f[N];
int get(int x) {return fa[x] == x?x:fa[x]=get(fa[x]);}
int main() {
qr(n);
for(int i=1;i<=n;i++) qr(x[i]),qr(y[x[i]]);
for(int i=1;i<=n;i++) {
fa[i]=i; sz[i]=1; f[i]=y[i];
while(top&&f[sta[top]]<y[i]) {
int t=get(sta[top--]);
if(t^i) fa[t]=i,sz[i] += sz[t],f[i]=min(f[i],f[t]);
}
sta[++top]=i;
}
for(int i=1;i<=n;i++) pr2(sz[get(x[i])]);
return 0;
}
由上面的实现可以发现一个连通块的编号连续(可以用归纳证明)
所以我们考虑什么情况下i,i+1i,i+1i,i+1在不同连通块.
要使得[1,i],(i,n][1,i],(i,n][1,i],(i,n]没有边,必须让[1,i][1,i][1,i]的每个点都大于[i+1,n][i+1,n][i+1,n]的任意点.
即[1,i][1,i][1,i]覆盖值域[n−i+1,n][n-i+1,n][n−i+1,n].
总复杂度为O(n)O(n)O(n).
int n,x[N],y[N],sz[N],last,p;
bool v[N];
int main() {
qr(n);
for(int i=1;i<=n;i++) qr(x[i]),qr(y[x[i]]);
p=n; last=1;
for(int i=1;i<=n;i++) {
v[y[i]]=1;
while(v[p]) p--;
if(n-p==i) {
int s=i-last+1;
while(last<=i) sz[last++]=s;
}
}
for(int i=1;i<=n;i++) pr2(sz[x[i]]);
return 0;
}
B Sum is Multiple
求最小的kkk满足n∣(1+2+...+k)n|(1+2+...+k)n∣(1+2+...+k).(n≤1e15n\le 1e15n≤1e15)
转化得:2n∣k(k+1)2n|k(k+1)2n∣k(k+1).
因为k,k+1k,k+1k,k+1互质,所以2n2n2n中的一些质因子由kkk处理,其他由k+1k+1k+1处理.
设s∣2n,gcd(s,t=2n/s)=1,s∣k,t∣(k+1)s|2n,\gcd(s,t=2n/s)=1,s|k,t|(k+1)s∣2n,gcd(s,t=2n/s)=1,s∣k,t∣(k+1).
设k=fsk=fsk=fs,因为t∣(k+1)t|(k+1)t∣(k+1),所以可得:
fs+1≡0(mod t)→fs≡−1(mod t)fs+1\equiv 0(\mod t)\rightarrow fs\equiv -1(\mod t)fs+1≡0(modt)→fs≡−1(modt)
我们只要求−s-s−s的逆元即可.
因为总质因子个数p≤14p\le 14p≤14,所以我们用2p2^p2p暴力枚举即可.
总复杂度为O(2plogn)O(2^p \log n)O(2plogn).
ll n,ans;
ll p[N],tot,c[1<<16];
void exgcd(ll &x,ll &y,ll a,ll b) {
if(!a) {x=0; y=1; return ;}
exgcd(y,x,b%a,a); x -= b/a*y;
}
ll inv(ll a,ll b) {
a=(2*b-a)%b;
ll x,y; exgcd(x,y,a,b);
return (x%b+b)%b;
}
void div(ll x) {
for(ll i=2;i*i<=x;i++) if(x%i == 0) {
p[tot]=x;
while(x%i==0) x/=i;
p[tot++] /= x;
}
if(x>1) p[tot++]=x;
}
int main() {
qr(n); div(n*2); c[0]=1;
for(int i=0;i<tot;i++) c[1<<i]=p[i];
if(n==1) puts("1"),exit(0);
if(n&1) ans=n-1;
else ans=n;
for(int i=1;i+1<(1<<tot);i++) {
c[i]=c[i&(i-1)]*c[i&(-i)];
ll x=c[i],y=2*n/x;
ans=min(ans,x*inv(x,y));
}
pr2(ans);
}
C Moving Pieces
裸费用流.
#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define IT iterator
#define vi vector<int>
#define TP template<class o>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=55,size=1<<20,mod=998244353,inf=2e9;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr1(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar('\n');
}
int n,m,ans,st,ed;
char s[N][N];
int id(int x,int y) {return (x-1)*m+y;}
struct edge{int y,next,c,d; } a[N*N*8]; int len=1,last[N*N];
void ins(int x,int y,int c,int d) {a[++len]=(edge){y,last[x],c,d}; last[x]=len;}
void add(int x,int y,int c,int d) {ins(x,y,c,d); ins(y,x,0,-d);}
int d[N*N],q[N*N],l,r,pre[N*N];
bool vis[N*N];
void EK() {
while(233) {
memset(d,-63,sizeof(d));
l=1; r=2; q[l]=st; pre[ed]=0; d[st]=0; vis[st]=1;
while(l!=r) {
int x=q[l++]; if(l==N*N) l=1; vis[x]=0;
for(int k=last[x],y;k;k=a[k].next) {
y=a[k].y;
if(a[k].c&&d[x]+a[k].d>d[y]) {
d[y]=d[x]+a[k].d;
pre[y]=k^1;
if(!vis[y]) {
q[r++]=y;
if(r==N*N) r=1;
}
}
}
}
if(!pre[ed]) return ;
ans += d[ed]; int x=ed,k;
while(x^st) {
k=pre[x];
a[k].c++;
a[k^1].c--;
x=a[k].y;
}
}
}
void solve() {
qr(n); qr(m); st=n*m+1; ed=st+1;
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) {
if(s[i][j]!='#') {
if(i<n&&s[i+1][j]!='#') add(id(i,j),id(i+1,j),inf,1);
if(j<m&&s[i][j+1]!='#') add(id(i,j),id(i,j+1),inf,1);
add(id(i,j),ed,1,0);
if(s[i][j]=='o') add(st,id(i,j),1,0);
}
}
EK(); pr2(ans);
}
int main() {
solve();
}
D Keep Distances
给定一个长度为nnn的递增数组xxx和参数kkk.
一个集合sss合法当且仅当任意不同元素i,j,∣xi−xj∣≥ki,j,|x_i-x_j|\ge ki,j,∣xi−xj∣≥k.
有qqq组询问,每组询问有参数L,RL,RL,R.
此时每个元素必须∈[L,R]\in[L,R]∈[L,R].
求最大集合的并集大小.
设a1<a2<...<ama_1<a_2<...<a_ma1<a2<...<am为一组字典序最小的解(贪心地从LLL开始每次取最小的后继),b1<b2<...<bmb_1<b_2<...<b_mb1<b2<...<bm为字典序最大的一组解(从RRR开始贪心取最大后继).
那么一定有a1≤b1<a2≤b2<a3≤b3<....<am≤bma_1\le b_1<a_2\le b_2<a_3\le b_3<....<a_m\le b_ma1≤b1<a2≤b2<a3≤b3<....<am≤bm.
假设存在bi≥ai+1b_i\ge a_{i+1}bi≥ai+1,那么有(a1,a2...ai+1,bi+1,..bm)(a_1,a_2...a_{i+1},b_{i+1},..b_m)(a1,a2...ai+1,bi+1,..bm)一组大小为m+1m+1m+1的解,与最大性矛盾.
现在证明∀bi<p<ai+1\forall b_i<p<a_{i+1}∀bi<p<ai+1,ppp为集合中的元素时,集合不能为最大.
因为左边至多取i−1i-1i−1,右边至多取m−i−1m-i-1m−i−1,所以最大取到m−1m-1m−1.
那么ans=∑i=1mbi−ai+1ans=\sum_{i=1}^m b_i-a_i+1ans=∑i=1mbi−ai+1.
#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define IT iterator
#define vi vector<int>
#define TP template<class o>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=2e5+10,size=1<<20,mod=998244353,inf=2e9;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr1(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar('\n');
}
int n,m,q,lg,x[N],r[N][20],l[N][20];
ll sl[N][20],sr[N][20];
int main() {
qr(n); qr(m);
for(int i=1;i<=n;i++) qr(x[i]);
for(int i=1;i<=n;i++) {
r[i][0]=r[i-1][0];
while(r[i][0]<=n&&x[r[i][0]]-x[i]<m) r[i][0]++;
sr[i][0]=r[i][0]-1;
}
l[n+1][0]=n;
for(int i=n;i;i--) {
l[i][0]=l[i+1][0];
while(l[i][0]&&x[i]-x[l[i][0]]<m) l[i][0]--;
sl[i][0]=l[i][0];
}
for(int i=0;i<20;i++) r[n+1][i]=n+1;
for(int j=1;(1<<j)<=n;j++,lg++)
for(int i=1;i<=n;i++) {
l[i][j]=l[l[i][j-1]][j-1];
sl[i][j]=sl[i][j-1]+sl[l[i][j-1]][j-1];
r[i][j]=r[r[i][j-1]][j-1];
sr[i][j]=sr[i][j-1]+sr[r[i][j-1]][j-1];
}
qr(q); while(q--) {
int L,R; qr(L); qr(R); ll ans=0;
ans -= L-1;
for(int v=L,i=lg;i>=0;i--)
if(r[v][i]<=R)
ans -= sr[v][i],v=r[v][i];
ans += R;
for(int v=R,i=lg;i>=0;i--)
if(l[v][i]>=L)
ans += sl[v][i],v=l[v][i];
pr2(ans);
}
return 0;
}
E Shuffle Window
给定一个nnn的排列ppp.然后令i=1...n−ki=1...n-ki=1...n−k进行以下操作:
random_shuffle(p+i,p+k+1)random\_shuffle(p+i,p+k+1)random_shuffle(p+i,p+k+1).
问最后的期望逆序对数量.
n≤2e5n\le 2e5n≤2e5.
对一个序列进行两次random_shufflerandom\_shufflerandom_shuffle等价于进行一次.
所以题目可以转化为:
维护一个大小为kkk的多重集sss,初始s={p1,p2....pk}s=\{p_1,p_2....p_k\}s={p1,p2....pk}
然后对于每一个i≤n−k+1i\le n-k+1i≤n−k+1,选出一个数为pi′p_i'pi′,然后加入pi+kp_{i+k}pi+k.
最后乱排sss,放入序列.
设fi=max(i−k,0)f_i=\max(i-k,0)fi=max(i−k,0)表示最早加入集合的时间.
我们考虑i<ji<ji<j的数对相对关系交换的概率.
设p=k−1kp=\dfrac{k-1}{k}p=kk−1表示一个多重集内的数活一轮的概率.
那么我们要先把iii移动到jjj加入多重集的时候,总概率为pfj−fip^{f_j-f_i}pfj−fi.
然后在一个多重集的时候,有12\dfrac 1221的概率先后顺序发生改变.
所以总体来看i<ji<ji<j,最后发生位置相对变化的概率为pfj−fi2\dfrac {p^{f_j-f_i}}22pfj−fi.
固定jjj,则总代价为∑i=1j−1[ai>aj](1−pfj−fi2) + [ai<aj]pfj−fi2\sum_{i=1}^{j-1} [a_i>a_j](1-\dfrac {p^{f_j-f_i}}2)~~+~~[a_i<a_j]\dfrac {p^{f_j-f_i}}2∑i=1j−1[ai>aj](1−2pfj−fi) + [ai<aj]2pfj−fi.用树状数组维护1pfi\dfrac 1{p^{f_i}}pfi1即可.
#include<bits/stdc++.h>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pb push_back
#define IT iterator
#define vi vector<int>
#define TP template<class o>
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=2e5+10,size=1<<20,mod=998244353,inf=2e9;
//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
char c=gc; x=0; int f=1;
while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
while(isdigit(c)) x=x*10+c-'0',c=gc;
x*=f;
}
template<class o> void qw(o x) {
if(x/10) qw(x/10);
putchar(x%10+'0');
}
template<class o> void pr1(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
if(x<0)x=-x,putchar('-');
qw(x); putchar('\n');
}
ll p[N],np[N],n,k,s,cnt,ans;
int c[N],a[N];
TP void upd(o &x,int y) {x += y; if(x>=mod) x -= mod;}
void add(int x,int y) {upd(s,y); for( ;x<=n;x += x&-x) upd(c[x],y); }
int ask(int x) {ll y=0; for( ; x;x -= x&-x) y += c[x]; return y%mod; }
void clear() {memset(c+1,0,sizeof(int)*n); s=0;}
ll mult(ll a,ll b,ll p) {
a=(a%p+p)%p; b=(b%p+p)%p;
ll c=(ld)a*b/p;
return a*b-c*p;
}
ll gcd(ll a,ll b) {return !a?b:gcd(b%a,a);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=c*a%mod;
b /= 2; a=a*a%mod;
}
return c;
}
ll Power(ll a,ll b=mod-2) {
ll c=1;
while(b) {
if(b&1) c=mult(c,a,mod);
b /= 2; a=mult(a,a,mod);
}
return c;
}
int main() {
qr(n); qr(k);
for(int i=1;i<=n;i++)
qr(a[i]),add(a[i],1),cnt += i-ask(a[i]);
p[0]=np[0]=1; p[1]=(k-1)*power(k)%mod; np[1]=power(p[1]); clear();
for(int i=2;i<=n;i++) p[i]=p[i-1]*p[1]%mod,np[i]=np[i-1]*np[1]%mod;
for(int i=1;i<=n;i++) {
int f=max(i-k,0LL);
ans += p[f]*(2*ask(a[i])-s+mod)%mod;
add(a[i],np[f]);
}
pr2((cnt+ans%mod*(mod+1)/2%mod)%mod); return 0;
}