Codeforces Round #763 (Div. 2)

A

直接 \(O(1)\) 用结论搞出来即可,但赛时发现范围很小就直接模拟了(注意到机器人在撞到上面和左面的墙并发生变速之前一定能够清除,只需要模拟撞下面、右面的墙)

int main(){
	int T; cin>>T;
	while(T--){
		int n, m, sx, sy, tx, ty;
		cin>>n>>m>>sx>>sy>>tx>>ty;
		
		int dx=1, dy=1;
		int res=0;
		rep(i,1,420){
			if(sx==tx || sy==ty) break;
			if(sx==n) dx=-dx;
			if(sy==m) dy=-dy;
			sx+=dx, sy+=dy;
			res++;
		}
		cout<<res<<endl;
	}
	return 0;
}

B

对于每个区间,通过枚举断点,肯定能够找到对应的两个子区间(如果断点在端点那就是一个),模拟即可。

const int N=1010;
 
pii q[N];
 
#define x first
#define y second
 
int main(){
	int T; cin>>T;
	while(T--){
		int n; cin>>n;
		set<pii> st;
		
		rep(i,1,n){
			int x, y; read(x), read(y);
			q[i]={x, y};
			st.insert(q[i]);
		}
		
		rep(i,1,n){
			auto [x, y]=q[i];
			if(x==y){
				cout<<x<<' '<<x<<' '<<x<<endl;
				continue;
			}
			rep(j,x,y){
				if(j==x){
					if(st.count({x+1, y})){
						cout<<x<<' '<<y<<' '<<x<<endl;
						break;
					}
				}
				if(j==y){
					if(st.count({x, y-1})){
						cout<<x<<' '<<y<<' '<<y<<endl;
						break;
					}
				}
				if(st.count({x, j-1}) && st.count({j+1, y})){
					cout<<x<<' '<<y<<' '<<j<<endl;
					break;
				}
			}
		}
		// puts("");
	}
	return 0;
}

C

对于这种最大化最小值的问题自然是二分

设现在二分出一个 \(k\),也就是操作后元素都要不小于 \(k\),现在检测其可行性

考虑贪心,为了防止前面的决策影响后面,我们从后面开始决策:我们自然是想要在保证后面大于 \(k\) 的前提下尽可能将物品分给前面的,最后我们检查一下决策后是否保证所有元素个数大于等于 \(k\) 即可。

const int N=2e5+5;
 
int a[N], b[N];
int n;
 
bool ok(int k){
	rep(i,1,n) b[i]=a[i];
	dwn(i,n,3){
		int h=min(a[i]/3, (b[i]-k)/3);
		b[i-1]+=h, b[i-2]+=2*h;
	}
	rep(i,1,n) if(b[i]<k) return false;
	return true;
}
 
signed main(){
	int T; cin>>T;
	while(T--){
		cin>>n;
		rep(i,1,n) read(a[i]);
		
		int l=1, r=1e10;
		while(l<r){
			int mid=l+r+1>>1;
			if(ok(mid)) l=mid;
			else r=mid-1;
		}		
		cout<<l<<endl;
	}
	return 0;
}

D

赛时我考虑将机器人可以清扫到污渍的点记为关键点,然后将关键点看成图论中的,边权是关键点之间的距离,然后得到一个环,但是写挂了呜呜。

后来看了题解才发现可以写得很简单。

记机器人执行清扫的概率为 \(\overline{p}\)

我们设从出发点出发,期望清扫到污渍的步数为 \(x\),记机器人返回出发点且和最初出发时的朝向的步数为 \(k\)

设出发点的后继期望清扫到污渍的步数为 \(y\),那么 \(x\)\(y\) 的关系为:\(x=w(1+y)\)

其中,如果出发点为关键点,那么 \(w=\overline{p}\),否则为 \(1\)

那么我们有 \(x = w_1(1 + w_2(1 + \dots w_k(1 + x)\dots))\)

发现这其实是一个线性方程,可以化成 \(x=ux+v\) 的形式,因此可以逆向考虑(考虑得到右式),将 \(u,v\) 统计出来,细节见代码。

const int N=1e5+5, mod=1e9+7;

ll fpow(ll x, ll p){
    ll res=1;
    for(; p; p>>=1, x=x*x%mod)
        if(p&1) res=res*x%mod;
    return res%mod;
}

ll inv(ll x){
	return fpow(x, mod-2)%mod;
}

int add(int a, int b){
	return ((a+b)%mod+mod)%mod;
}

int mul(int a, int b){
	return a*b%mod;
}

signed main(){
	int T; cin>>T;
	while(T--){
		int n, m, sx, sy, tx, ty, p;
		cin>>n>>m>>sx>>sy>>tx>>ty>>p;
		p=mul(add(100, -p), inv(100));
		
		int ux=sx, uy=sy;
		int u=1, v=0;
		int dx=-1, dy=-1;
		rep(i,1,4*(n-1)*(m-1)){
			if(ux+dx<1 || ux+dx>n) dx=-dx;
			if(uy+dy<1 || uy+dy>m) dy=-dy;
			
			ux+=dx, uy+=dy;
			v=add(v, 1);
			int w;
			if(ux==tx || uy==ty) w=p;
			else w=1;
			u=mul(u, w), v=mul(v, w);
		}
		
		cout<<(mul(v, inv(add(1, -u))))<<endl;
	}
	return 0;
}
posted @ 2021-12-30 00:20  HinanawiTenshi  阅读(137)  评论(0编辑  收藏  举报