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

来源:互联网 发布:屏幕截图软件下载 编辑:程序博客网 时间:2024/05/16 00:39

题目链接: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;}



0 0
原创粉丝点击