超超超超超爽的一道题!
这题啊……真的是无话可说了,做完浑身舒畅的那种。
我们先不考虑 corner case。
首先肯定是按套路假设一轮过完之后起点移动的向量是
我们考虑每一次的到达的点其实是很有规律的,对应点坐标之间会恰好差一个
具体来说,我们用
这样的话,我们如果先暴力走一轮,那么对于一个走到的点
那么我们考虑正方形的四个顶点。我们会发现,如果对于一个
接下来是一些 corner case。
-
dx<0
把所有 E 和 W 交换就好了。
-
dx=0,dy\not=0
把
-
dx=dy=0
每一轮都一样,走一轮就好了。可以把
代码(采用的区间是左闭右开的):
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>itv;
int dx,dy;
map<itv,set<itv>>cnt;
void init(){
int n,k;
string s;
cin>>n>>k>>s;
auto op=[](int&x,int&y,char c){
switch(c){
case 'E':++x;break;
case 'N':++y;break;
case 'W':--x;break;
case 'S':--y;break;
}
};
for(char c:s)op(dx,dy,c);
auto trans=[&s](vector<pair<char,char>>trs){
for(char&c:s)
for(auto[c1,c2]:trs)
if(c==c1)c=c2;
else if(c==c2)c=c1;
};
if(!dx){
swap(dx,dy),trans({{'E','N'},{'W','S'}});
if(!dx)dx=250637,k=1;
}
if(dx<0)dx=-dx,trans({{'E','W'}});
auto ins=[](itv pos,itv val){
auto&st=cnt[pos];
auto itl=st.lower_bound({val.first,INT_MIN});
if(itl!=st.begin()&&prev(itl)->second>=val.first)--itl;
auto itr=st.upper_bound({val.second,INT_MAX});
if(itl==itr)st.insert(val);
else{
int l=min(itl->first,val.first),r=max(prev(itr)->second,val.second);
st.erase(itl,itr),st.emplace(l,r);
}
};
ins({0,0},{0,1});
for(int x=0,y=0;char c:s){
op(x,y,c);
int dt=x/dx,px=x-dt*dx,py=y-dt*dy;
if(px<0)px+=dx,py+=dy,--dt;
ins({px,py},{dt,k+dt});
}
}
signed main(){
long long ans=0;
auto atval=[](int x,int y){
vector<itv>ret;
int dt=0;
if(x==dx)x-=dx,y-=dy,dt=1;
if(auto it=cnt.find({x,y});it!=cnt.end()){
ret.reserve(it->second.size());
copy(it->second.begin(),it->second.end(),back_inserter(ret));
for(auto&[l,r]:ret)l-=dt,r-=dt;
}
return ret;
};
auto merge=[](auto x,auto y){
vector<itv>ret;
for(auto pos=y.begin();auto[l,r]:x)
while(pos!=y.end()){
while(pos!=y.end()&&pos->second<=l)++pos;
if(pos==y.end()||pos->first>=r)break;
ret.emplace_back(max(l,pos->first),min(r,pos->second));
if(pos->second>=r)break;
else ++pos;
}
return ret;
};
for(init();auto[pos,iv]:cnt){
auto[x,y]=pos;
for(auto[l,r]:merge(merge(atval(x,y),atval(x+1,y+1)),merge(atval(x+1,y),atval(x,y+1))))
ans+=r-l;
}
return cout<<ans<<endl,0;
}