CF Good Bye 2015 F. New Year and Cleaning(思维)

题目链接:http://codeforces.com/contest/611/problem/F

题意:有一个方块矩阵h*w(h,w<=500000),一个机器人在一个控制序列(n<=500000)的循环作用下可以在矩阵中在上、下、左、右方向上移动,移动一次花费一分钟时间,每次将要超出矩阵范围时机器人停止运动。现将矩阵中的每一个方格作为起始点,即机器人以某一个方格为起点运动停止后,将其放置在下一个方格中开始运动,问多少时间可以将这个过程完成。

解题思路:脑洞题,记录每一次移动时移动的步长,移动一步时可能会有某一行或某一列被消去,那么这一行或列对答案的贡献就是面积乘以步长,维护当前矩阵的大小(左上和右下的坐标),不断模拟机器人移动,直到矩阵被完全消去。

实现细节:

1.建立坐标系,列数增加方向代表x轴正方向,行数增加方向代表y轴正方向,当前矩阵范围为(min_x,min_y)~(max_x,max_y);

2.记录当前x和y的变化值dx和dy,维护x和y的当前移动的最大范围【mx1,mx2】和【my1,my2】;

3.对于每一个移动指令,根据dx和【mx1,mx2】判断是否会有列消去,根据dy和【my1,my2】判断是否会有列消去(具体看代码);

4.当模拟一次控制序列后,如果矩阵没有被完全消去且dx=dy=0,那么这个矩阵无法被消去,输出-1;

以上是纯模拟过程,复杂度最大可以达到O【(h+w)*n】,导致TLE,所以要优化。

优化方法:

O(n)时间模拟两次,记录第二次模拟时发生消去的位置,那么可以发现以后的模拟中消去操作都发生在这些位置,然后循环模拟这些位置的操作,直至矩阵被完全消去。复杂度为O(h+w+n)。

注意,步长最大能够达到max(h,w)*n,要用long long。

此题还有一个挑战版本:题意不变,n的范围不变,但(h,w<=1e9),表示目前还没想出来^_^,留个坑。

以下为AC代码(CF上标程只有60行,而我写了120行):

MY_self:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <stack>
#include <queue>
using namespace std;

typedef long long LL;
const int mod=1e9+7;

char s[500005];
vector<int>  use;

int n;
int max_x,min_x,max_y,min_y;
int dx,dy;
int mx1,mx2,my1,my2,is;
int ans;
LL cnt;

void del(bool mem){
    for(int i=0;i<n;i++){
        if(max_x<min_x||max_y<min_y)
            break;
        cnt++;
        if(s[i]=='R'){
            if(dx>=mx1){
                if(mem) use.push_back(i);
                mx1++;
                max_x--;
                ans=(ans+(max_y-min_y+1)*cnt%mod)%mod;
            }
            dx++;
        }
        if(s[i]=='L'){
            if(dx<=mx2){
                if(mem) use.push_back(i);
                mx2--;
                min_x++;
                ans=(ans+(max_y-min_y+1)*cnt%mod)%mod;
            }
            dx--;
        }
        if(s[i]=='D'){
            if(dy>=my1){
                if(mem) use.push_back(i);
                my1++;
                max_y--;
                ans=(ans+(max_x-min_x+1)*cnt%mod)%mod;
            }
            dy++;
        }
        if(s[i]=='U'){
            if(dy<=my2){
                if(mem) use.push_back(i);
                my2--;
                min_y++;
                ans=(ans+(max_x-min_x+1)*cnt%mod)%mod;
            }
            dy--;
        }
    }
}


int main (){
    int h,w;
    while(scanf("%d%d%d",&n,&h,&w)!=EOF){
        scanf("%s",s);
        max_x=w,min_x=1,max_y=h,min_y=1;
        dx=0,dy=0;
        mx1=0,mx2=0,my1=0,my2=0;
        ans=0,cnt=0,is=1;
        del(0);             //第一次删除,无记忆操作
        if(is&&dx==0&&dy==0)   is=0;
        else{
            use.clear();
            del(1);         //第二次删除,有记忆操作
            int cur=0;
            int first=1;
            while(max_x>=min_x && max_y>=min_y){       //循环操作(优化部分)
                if(cur==0){
                    if(first==0)
                        cnt+=n-1-use[use.size()-1]+use[0]+1;
                    else {
                        cnt+=use[0]+1;
                        first=0;
                    }
                }
                else        cnt+=use[cur]-use[cur-1];
                switch(s[use[cur]]){
                    case 'R':
                        max_x--;
                        ans=(ans+(max_y-min_y+1)*cnt%mod)%mod;
                        break;
                    case 'L':
                        min_x++;
                        ans=(ans+(max_y-min_y+1)*cnt%mod)%mod;
                        break;
                    case 'U':
                        min_y++;
                        ans=(ans+(max_x-min_x+1)*cnt%mod)%mod;
                        break;
                    case 'D':
                        max_y--;
                        ans=(ans+(max_x-min_x+1)*cnt%mod)%mod;
                        break;
                }
                if(cur==((int)use.size()-1))  cur=0;
                else  cur++;
            }
        }
        if(is!=0)
            printf("%d\n",ans);
        else
            printf("-1\n");
    }
    return 0;
}

CF标程:

// Cleaning Robot (F), by Errichto
// AC, O(w+h+n)
#include<bits/stdc++.h>
using namespace std;
#define FOR(i,a,b) for(int i = (a); i <= (b); ++i)
#define RI(i,n) FOR(i,1,(n))
#define REP(i,n) FOR(i,0,(n)-1)
typedef long long ll;
 
const int nax = 5e5 + 5;
const int mod = 1e9 + 7;
char sl[nax];
 
int n;
int ans;
int low[2], high[2], curr[2], dimension[2];
 
bool f(ll moves, bool cheating) {
	if(moves != 0 && moves % n == 0 && curr[0] == 0 && curr[1] == 0) {
		puts("-1");
		exit(0);
	}
	char type = sl[moves%n];
	if(type == 'L') cheating ? curr[0] = high[0]+1 : ++curr[0];
	else if(type == 'R') cheating ? curr[0] = low[0]-1 : --curr[0];
	else if(type == 'U') cheating ? curr[1] = high[1]+1 : ++curr[1];
	else if(type == 'D') cheating ? curr[1] = low[1]-1 : --curr[1];
	else assert(false);
	bool something_happened = false;
	REP(i, 2) {
		if(curr[i] < low[i] || curr[i] > high[i]) {
			ans = (ans + (moves + 1) % mod * dimension[i^1]) % mod;
			--dimension[i];
			something_happened = true;
		}
		if(curr[i] < low[i]) low[i] = curr[i];
		if(curr[i] > high[i]) high[i] = curr[i];
	}
	return something_happened;
}
 
bool inGame() { return dimension[0] > 0 && dimension[1] > 0; }
 
int main() {
	scanf("%d%d%d", &n, &dimension[1], &dimension[0]);
	scanf("%s", sl);
 
	for(ll moves = 0; inGame() && moves < n; ++moves)
		f(moves, false);
	vector<int> w;
	for(ll moves = n; inGame() && moves < 2 * n; ++moves)
		if(f(moves, false)) w.push_back((int) moves % n);
 
 
	for(ll k = 2; inGame(); ++k)
		for(int moves : w) if(inGame())
			f(k*n + moves, true);
	printf("%d\n", ans);
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值