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;}
- CF Good Bye 2015 F. New Year and Cleaning(思维)
- CF Good Bye 2015 A- New Year and Days(CF611A)
- CF Good Bye 2015 C- New Year and Domino(CF611C)
- CF Good Bye 2015 C. New Year and Domino && D. New Year and Ancient Prophecy (DP)
- CF Good Bye 2015 E. New Year and Three Musketeers(贪心+枚举)
- Good Bye 2016 C. New Year and Rating思维
- CF Good Bye 2015 B- New Year and Old Property(CF611B)
- Codeforces Good Bye 2015 C. New Year and Domino (预处理)
- Good Bye 2015 C New Year and Domino(dp)
- Codeforces Good Bye 2015 E. New Year and Three Musketeers
- Good Bye 2015 D. New Year and Ancient Prophecy
- Good BYe 2015 D New Year and Ancient Prophecy
- 【Codeforces Good Bye 2015】D. New Year and Ancient Prophecy
- Good Bye 2015 D. New Year and Ancient Prophecy
- codeforces Good Bye 2015 C - New Year and Domino
- codeforces Good Bye 2015 D. New Year and Ancient Prophecy
- codeforces Good Bye 2015 E. New Year and Three Musketeers
- codeforces-Good Bye 2015-New Year and Domino
- 【设计模式】迭代器模式
- [Github] fatal: remote error: You can't push to git 解决办法
- 遇见更加美好的自己!
- list转字符串数组
- 解决UITableViewStylePlain方式headerView顶端 滞留的代码
- CF Good Bye 2015 F. New Year and Cleaning(思维)
- Android-Universal-Image-Loader是一个开源的UI组件程序
- 自定义PopupWindow实现Spinner
- Android 开发中,有哪些坑需要注意?
- 挑战面试编程:查找数组中第k大的数
- table表格锁定任意数量列或行
- Azure Storm入门(二)—— 事务处理
- eclipse 中设置content assist 如何设置空格不上屏
- GSM模块--SIM900A短信功能