Loading

ABC219_F Cleaning Robot 同余

ABC219_F Cleaning Robot 同余

题意

初始有在\((0,0)\)位置有机器在二维平面,给定长度为\(N\)的上下左右合成的命令,命令重复\(K\)次,求经过的不同点个数

\[1 \leq K \leq 10^{12}\\ 1 \leq N \leq 2\times 10^5 \]

分析

把前\(N\)次走过的坐标写下来,记\((x_N,y_N) = (a,b)\) 显然有第\(i\)轮走过的坐标只是第一轮基础上加上\(((i - 1)a,(i-1)b)\)

放到平面上,可以看成有至多\(N\)条本质不同,斜率相同的直线

计数的实际上是对某条直线找到起点,横坐标每次走\(a\)的点

冲突是因为某条直线上可以有多个起点,这些点两两同余,因此可在取模意义下计数,只需对直线上每个点计算模意义下的"距离"(几步可以走到),排序后对\(K\)取min即可,注意点的同余,可以用pair类比一维的整数

两个简化代码的技巧:若模数为0,需要特殊讨论,不妨对\(b\) 取swap;若\(a <0\),不妨对\(y\)轴对称,显然不影响答案

代码

int main(){
	scanf("%s",s);
	ll k;
	scanf("%lld",&k);
	int len = strlen(s);
	int a = 0;
	int b = 0;
	ll ans = 0;
	vector<pii> v(len + 1);
    v[0] = make_pair(0,0);
	map<pii,int> t;
    t[make_pair(0,0)] = 1;
	int tmp = 1;
	for(int i = 0;i < len;i++){
		if(s[i] == 'L') a--;
		else if(s[i] == 'R') a++;
		else if(s[i] == 'U') b--;
		else b++;
	    v[i + 1] = make_pair(a,b);
        if(!t.count(v[i + 1])) t[v[i + 1]] = 1,tmp++;
    }
	if(!a && !b) {
		printf("%d",tmp);
		return 0;
	}
    if(!a) {
        swap(a,b);
        for(int i = 1;i <= len;i++)
            swap(v[i].fi,v[i].se);
    }
    if(a < 0) {
        a = -a;
        for(int i = 1;i <= len;i++)
            v[i].fi = -v[i].fi;
    }
    sort(all(v));
    map<pii,int> mp;
    for(int i = len;i >= 0;i--) {
        int lst = v[i].fi;
        v[i].fi = (v[i].fi % a + a) % a;
        int t = (lst - v[i].fi) / a;
        v[i].se -= (ll)t * b;
        if(mp.count(v[i])) 
            ans += min(k,(ll)mp[v[i]] - t);
        else ans += k;
        mp[v[i]] = t;
    }
    cout << ans;
}
posted @ 2021-10-21 15:44  MQFLLY  阅读(59)  评论(0编辑  收藏  举报