题解:P5102 [JOI 2016 Final] 领地 / Territory
lucky_baizq · · 题解
C.P5102 [JOI 2016 Final] 领地 / Territory - 洛谷
题意:你会按照指令上下左右走,时限可以完整模拟一轮,但是需要重复走
很好的题目喵喵喵!
考虑完整的一轮后你到达的终点
就类似于这样偏移此时
考虑把第一次操作暴力模拟一遍,记录
Code:太阳只有一个,却遍地都是阳光,相信未来时光明的。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
int dx,dy;
map<pii,set<pii>>mp;
int n,k,ans;
string s;
void p(char c,int& dx,int&dy){
if(c=='E')++dx;if(c=='N')++dy;
if(c=='W')--dx;if(c=='S')--dy;
}
void cha(pii x,pii w){
auto&s=mp[x];
auto l=s.lower_bound({w.fi,-2e9});
if(l!=s.begin()&&prev(l)->se>=w.fi)l--;
auto r=s.upper_bound({w.se,2e9});
if(l==r)s.insert(w);
else{
int l1=min(l->fi,w.fi),r1=max(prev(r)->se,w.se);
s.erase(l,r),s.emplace(l1,r1);
}
}
auto get(int x,int y){
vector<pii> v;
int t=0;if(x==dx)x-=dx,y-=dy,t=1;
auto it=mp.find({x,y});
if(it!=mp.end()){
v.reserve(it->se.size());
copy(it->second.begin(),it->second.end(),back_inserter(v));
for(auto&[l,r]:v)l-=t,r-=t;
}
return v;
}
auto he(auto x,auto y){
vector<pii> v;
for(auto it=y.begin();auto [l,r]:x){
while(it!=y.end()){
while(it!=y.end()&&it->se<=l)it++;
if(it==y.end()||it->fi>=r)break;
v.push_back({max(it->fi,l),min(r,it->se)});
if(it->se>=r)break;
else it++;
}
}
return v;
}
signed main(){
cin>>n>>k>>s;
for(char c:s){
p(c,dx,dy);
}
if(!dx){
swap(dx,dy);for(char&c:s){
if(c=='E')c='N';
else if(c=='N')c='E';
if(c=='W')c='S';
else if(c=='S')c='W';
}
if(!dx)dx=114514,k=1;
}
if(dx<0){dx=-dx;for(char&c:s)if(c=='E')c='W';else if(c=='W')c='E';}
int x=0,y=0;
cha({0,0},{0,1});//左闭右开
for(char c:s){
p(c,x,y);
int t=x/dx,px=x-t*dx,py=y-t*dy;
if(px<0)t--,px+=dx,py+=dy;
cha({px,py},{t,t+k});
}
for(auto [p,v]:mp){
auto[x,y]=p;
for(auto[l,r]:he(he(get(x,y),get(x+1,y+1)),he(get(x,y+1),get(x+1,y))))
ans+=r-l;
}
cout<<ans;
return 0;
}