Atcoder AGC013 简要题解

传送门

Sorted Arrays

贪心到前面第一个非法位置转移。

#include 
using namespace std;
 
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
 
const int N=1e5+50;
int n,a[N],p[N][2],f[N];
 
int main() {
	n=rd();
	for(int i=1;i<=n;i++) a[i]=rd();
	for(int i=1;i<=n;i++) {
		p[i][0]=p[i-1][0];
		p[i][1]=p[i-1][1];
		if(a[i]>a[i-1]) p[i][1]=i-1;
		if(a[i]<a[i-1]) p[i][0]=i-1;
		f[i]=f[min(p[i][0],p[i][1])]+1;
	}  cout<<f[n]<<'\n';
}

Hamiltonish Path

随便放一条边在双端队列中,然后不断向两边扩展。

#include 
using namespace std;
 
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
 
const int N=2e5+50;
 
int n,m,inq[N];
vector <int> edge[N];
deque <int> q;
 
inline void F(int x) {q.push_front(x); inq[x]=1;}
inline void T(int x) {q.push_back(x); inq[x]=1;}
inline bool CF(int x) {
	for(auto v:edge[x]) if(!inq[v]) {F(v); return true;}
	return false;
}
inline bool CT(int x) {
	for(auto v:edge[x]) if(!inq[v]) {T(v); return true;}
	return false;
}
int main() {
	n=rd(), m=rd();
	for(int i=1;i<=m;i++) {
		int x=rd(), y=rd();
		edge[x].push_back(y);
		edge[y].push_back(x);
	} 
	for(int i=1;i<=n;i++) if(edge[i].size()) {F(i), T(edge[i].front()); break;}
	while(CF(q.front())); while(CT(q.back()));
	printf("%d\n",q.size());
	for(auto v:q) printf("%d ",v);
}

Ants on a Circle

最后蚂蚁的位置是确定的,彼此的顺序也是确定的。 每次有蚂蚁经过 0 0 0处排名会整体移动1。

#include 
using namespace std;
typedef long long LL;
 
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
 
const int N=1e5+50;
int n,cnt,L,T,a[N],b[N],w[N];
int main() {
	n=rd(), L=rd(), T=rd();
	for(int i=1;i<=n;i++) {
		a[i]=rd(), w[i]=(rd()==1 ? 1 : -1);
		b[i]=((a[i]+(LL)T*w[i])%L+L)%L;
		int dis=(w[i]>0 ? L-a[i] : a[i])+1;
		if(T>=dis) {
			cnt+=w[i]; int res=T-dis;
			cnt+=(res/L)*w[i];
			cnt=(cnt%n+n)%n;
		}
	} sort(b+1,b+n+1);
	for(int i=1;i<=n;i++) 
		printf("%d\n",b[(i+cnt-1)%n+1]);
}

Piling Up

考虑任意一个序列,他非法一定存在某个位置的前缀超过了范围。

那么DP的时候记录一下是否卡住过范围,就可以不重不漏了。

#include 
using namespace std;
typedef long long LL;
 
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-') f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
 
const int N=3e3+50, mod=1e9+7;
inline void add(int &x,int y) {x=(x+y>=mod) ? (x+y-mod) : (x+y);}
int n,m,f[N][N][2];
 
int main() {
	n=rd(), m=rd();
	for(int i=0;i<=n;i++) f[0][i][i==0]=1;
	for(int i=1;i<=m;i++) {
		for(int j=0;j<=n;++j) {
			if(j) add(f[i][j][j==1],f[i-1][j][0]), add(f[i][j][1],f[i-1][j][1]);
			if(j) add(f[i][j-1][j==1],f[i-1][j][0]), add(f[i][j-1][1],f[i-1][j][1]);
			if(n-j) add(f[i][j][0],f[i-1][j][0]), add(f[i][j][1],f[i-1][j][1]);
			if(n-j) add(f[i][j+1][0],f[i-1][j][0]), add(f[i][j+1][1],f[i-1][j][1]);
		}
	}
	int ans=0;
	for(int i=0;i<=n;i++) add(ans,f[m][i][1]);
	cout<<ans<<'\n';
}

Placing Squares

把问题转化为一个正方形里面可以放两个点,总共的方案数。

矩阵快速幂即可。

#include 
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
 
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
 
const int mod=1e9+7;
inline int add(int x,int y) {return (x+y>=mod) ? (x+y-mod) : (x+y);}
inline int dec(int x,int y) {return (x-y<0) ? (x-y+mod) : (x-y);}
inline int mul(int x,int y) {return (long long)x*y%mod;}
inline int power(int a,int b,int rs=1) {for(;b;b>>=1,a=mul(a,a)) if(b&1) rs=mul(rs,a); return rs;}
 
int n,m;
const int T1[3][3]={ {2,1,1},
					 {2,1,2},
					 {1,0,1} };
const int T2[3][3]={ {1,1,1},
					 {0,1,2},
					 {0,0,1} }; 
struct matrix {
	int a[3][3];
	matrix (int t=0) {memset(a,0,sizeof(a)); rep(i,0,2) a[i][i]=t;}
	friend inline matrix operator *(const matrix &a,const matrix &b) {
		matrix c(0);
		rep(i,0,2) rep(k,0,2) rep(j,0,2) c.a[i][j]=add(c.a[i][j],mul(a.a[i][k],b.a[k][j]));
		return c;
	}
	friend inline matrix operator ^(matrix a,int b) {
		matrix c(1);
		for(;b;b>>=1,a=a*a) if(b&1) c=c*a;
		return c;
	}
} A,tr1,tr2;
 
int main() {
	n=rd(), m=rd();
	A.a[0][0]=1;
	memcpy(tr1.a,T1,sizeof(T1));
	memcpy(tr2.a,T2,sizeof(T2));
	int lst=0;
	for(int i=1;i<=m;++i) {
		int nxt=rd();
		A=A*(tr1^(nxt-lst-1));
		A=A*tr2; lst=nxt;
	}
	A=A*(tr1^(n-lst)); 
	cout<<A.a[0][2]<<'\n';
}

Two Faced Cards

注意匹配完之后是一个括号序列。

放入最后一张卡(左括号)之前的后缀和一定形如 1 , 1 , 1 , 1 , 0 , 0 , 0 , 0 , . . 1,1,1,1,0,0,0,0,.. 1,1,1,1,0,0,0,0,..,我们需要预处理所有 n + 1 n+1 n+1个这样的代价。

先假设全部放在正面,然后从右到左贪心的修改区间,保证每个后缀 ≥ 0 \ge 0 0。 然后再从左往右,贪心保证每个前缀 ≥ 0 \ge 0 0即可。

#include 
using namespace std;
#define X first
#define Y second
typedef pair <int,int> pii;
 
const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}

const int N=1e5+50, INF=0x3f3f3f3f;
int n,bz=1,cnt;
int a[N],b[N],c[N],d[N],e[N],ans[N];
struct L {
	int l,r; 
	L(int l,int r) : l(l),r(r) {}
	friend inline bool operator <(const L &a,const L &b) {return a.l<b.l || (a.l==b.l && a.r>b.r);}
};
struct R {
	int l,r;
	R(int l,int r) : l(l),r(r) {}
	friend inline bool operator <(const R &a,const R &b) {return a.r<b.r || (a.r==b.r && a.l>b.l);}
};

multiset <int> lq[N];
multiset <int> rq[N];
multiset <L> ls; 
multiset <R> rs;

inline int kth(int x) {return lower_bound(c+1,c+n+2,x)-c;}
int main() {
	n=rd();
	for(int i=1;i<=n;i++) a[i]=rd(), b[i]=rd();
	for(int i=1;i<=n+1;i++) c[i]=rd(), d[i]=e[i]=1;
	sort(c+1,c+n+2);
	for(int i=1;i<=n && bz;i++) {
		if(a[i]>c[n+1] && b[i]>c[n+1]) bz=0;
		if(a[i]<=c[n+1]) {
			a[i]=kth(a[i]); b[i]=kth(b[i]);
			--d[a[i]]; --e[a[i]];
			if(b[i]<a[i]) rq[a[i]].insert(b[i]+1), lq[b[i]+1].insert(a[i]);
		} else --d[kth(b[i])], --e[kth(b[i])], ++cnt;
	}
	if(!bz) {for(int i=rd();i;i--) puts("-1"); return 0;}
	for(int i=n+1;i>=1 && bz;i--) {
		d[i]+=d[i+1];
		for(auto v:rq[i]) ls.insert(L(v,i));
		while(d[i]<0) {
			++cnt;
			if(!ls.size()) {bz=0; break;}
			L t=*ls.begin(); ls.erase(ls.begin());
			lq[t.l].erase(lq[t.l].find(t.r));
			++d[i]; --d[t.l-1];
			++e[t.r]; --e[t.l-1];
		}
	}
	if(!bz) {for(int i=rd();i;i--) puts("-1"); return 0;}
	for(int i=n;i>=1;i--) e[i]+=e[i+1];
	for(int i=1;i<=n+1;i++) {d[i]=e[i]-e[i-1];}
	for(int i=1;i<=n+1 && bz;i++) {
		d[i]+=d[i-1];
		for(auto v:lq[i]) rs.insert(R(i,v));
		while(d[i]<1) {
			++cnt;
			if(!rs.size()) {bz=0; cnt=INF; for(int j=i+1;j<=n+1;++j) ans[j]=cnt; break;}
			R t=*--rs.end(); rs.erase(--rs.end());
			++d[i]; --d[t.r+1];
		} ans[i]=cnt;
	}
	for(int i=rd();i;i--) {
		int x=rd(), y=rd();
		int w=INF;
		if(x<=c[n+1]) w=min(w,ans[kth(x)]);
		if(y<=c[n+1]) w=min(w,ans[kth(y)]+1);
		printf("%d\n",(w==INF) ? -1 : (n-w+1));
	}
}

你可能感兴趣的:(contest)