题解:P11078 「FSLOI Round I」迷雾

Subtask 1&2

很明显的暴力模拟,每到一个迷雾点,那就再后面更新符号,时间复杂度 O ⁡ ( q 2 ) \operatorname{O}(q^2) O(q2)

#include<iostream>
#include<algorithm>
#define MAXN 505
#define MAXM 200002
using namespace std;
int n,m,q,k,a[MAXM],b[MAXM];
char mp[MAXN][MAXN],c[MAXM];
int dy[4]={0,0,-1,1};
int dx[4]={1,-1,0,0};
inline int turn(char c){
	if(c=='D'){
		return 0;
	}
	if(c=='U'){
		return 1;
	}
	if(c=='L'){
		return 2;
	}
	return 3;
}
inline char change(char c){
	if(c=='U'){
		return 'D';
	}
	if(c=='D'){
		return 'U';
	}
	if(c=='L'){
		return 'R';
	}
	return 'L';
}
int main(){
	scanf("%d %d %d %d",&n,&m,&q,&k);
	for(int i=1;i<=n;++i){
		scanf("%s",mp[i]+1);
	}
	for(int i=1;i<=q;++i){
		scanf("\n%c %d %d",&c[i],&a[i],&b[i]);
	}
	int x=1,y=1;
	for(int i=1;i<=q;++i){
		x+=dx[turn(c[i])]*a[i];
		y+=dy[turn(c[i])]*a[i];
		x=min(max(x,1),n);
		y=min(max(y,1),m);
//		cout<<x<<" "<<y<<endl;
		if(mp[x][y]=='X'){
			for(int j=1;j<=b[i];++j){
				c[i+j*k]=change(c[i+j*k]);
			}
		}
//		for(int j=1;j<=q;++j){
//			cout<<c[j]<<" ";
//		}
//		cout<<endl;
	}
	printf("%d %d",x,y);
	return 0;
}

Subtask 3

考虑 k = 1 k=1 k=1 的情况,即每到一个迷雾点,就更新 [ i + 1 , i + b i ] [i+1,i+b_i] [i+1,i+bi],加上 1 1 1,当一个点它的值为偶数的时候,就会变回去,否则就要变。这个可以用维护差分数组的树状数组维护。时间复杂度 O ⁡ ( q log ⁡ q ) \operatorname{O}(q\log q) O(qlogq),仅限于 k = 1 k=1 k=1

#include<iostream>
#include<algorithm>
#define MAXN 505
#define MAXM 200002
using namespace std;
int n,m,q,k,a[MAXM],b[MAXM];
char mp[MAXN][MAXN],c[MAXM];
int tree[MAXM<<1];
int dy[4]={0,0,-1,1};
int dx[4]={1,-1,0,0};
inline int turn(char c){
	if(c=='D'){
		return 0;
	}
	if(c=='U'){
		return 1;
	}
	if(c=='L'){
		return 2;
	}
	return 3;
}
inline char change(char c){
	if(c=='U'){
		return 'D';
	}
	if(c=='D'){
		return 'U';
	}
	if(c=='L'){
		return 'R';
	}
	return 'L';
}
inline int lowbit(int x){
	return x&-x;
}
inline void modify(int p,int add){
	for(int i=p;i<MAXM;i+=lowbit(i)){
		tree[i]+=add;
	}
}
inline int query(int p){
	int ans=0;
	for(int i=p;i;i-=lowbit(i)){
		ans+=tree[i];
	}
	return ans;
}
inline void work(){
	int x=1,y=1;
	for(int i=1;i<=q;++i){
		if(query(i)%2==1){
			c[i]=change(c[i]);
		}
		x+=dx[turn(c[i])]*a[i];
		y+=dy[turn(c[i])]*a[i];
		x=min(max(x,1),n);
		y=min(max(y,1),m);
		if(mp[x][y]=='X'){
			modify(i+1,1);
			modify(i+b[i]+1,-1);
		}
	}
	printf("%d %d",x,y);
}
int main(){
	scanf("%d %d %d %d",&n,&m,&q,&k);
	for(int i=1;i<=n;++i){
		scanf("%s",mp[i]+1);
	}
	for(int i=1;i<=q;++i){
		scanf("\n%c %d %d",&c[i],&a[i],&b[i]);
	}
	if(k==1){
		work();
		return 0;
	}
	int x=1,y=1;
	for(int i=1;i<=q;++i){
		x+=dx[turn(c[i])]*a[i];
		y+=dy[turn(c[i])]*a[i];
		x=min(max(x,1),n);
		y=min(max(y,1),m);
		if(mp[x][y]=='X'){
			for(int j=1;j<=b[i];++j){
				c[i+j*k]=change(c[i+j*k]);
			}
		}
	}
	printf("%d %d",x,y);
	return 0;
}

Subtask 4&5

考虑到第 i i i 个节点只可能被 i − k , i − 2 × k , i − 3 × k … i-k,i-2\times k,i-3\times k\dots ik,i2×k,i3×k 更新到,也就是以 k k k 为模数, i i i 只可能更新到与其在模 k k k 意义下同余的点,考虑开 k k k 个树状数组,每一个维护 x × k + y = i x\times k+y=i x×k+y=i 中的 y y y x x x 就是维护值的下标,时间复杂度 O ⁡ ( q log ⁡ q ) \operatorname{O}(q\log q) O(qlogq)

#include<iostream>
#include<algorithm>
#include<cmath>
#define MAXN 505
#define MAXM 200002
#define MAXK 22
using namespace std;
int n,m,q,k,a[MAXM],b[MAXM];
char mp[MAXN][MAXN],c[MAXM];
int tree[MAXK][MAXM<<1];
int dy[4]={0,0,-1,1};
int dx[4]={1,-1,0,0};
inline int turn(char c){
	if(c=='D'){
		return 0;
	}
	if(c=='U'){
		return 1;
	}
	if(c=='L'){
		return 2;
	}
	return 3;
}
inline char change(char c){
	if(c=='U'){
		return 'D';
	}
	if(c=='D'){
		return 'U';
	}
	if(c=='L'){
		return 'R';
	}
	return 'L';
}
inline int lowbit(int x){
	return x&-x;
}
inline void modify(int ex,int p,int add){
	for(int i=p;i<MAXM;i+=lowbit(i)){
		tree[ex][i]+=add;
	}
}
inline int query(int ex,int p){
	int ans=0;
	for(int i=p;i;i-=lowbit(i)){
		ans+=tree[ex][i];
	}
	return ans;
}
int main(){
	scanf("%d %d %d %d",&n,&m,&q,&k);
	for(int i=1;i<=n;++i){
		scanf("%s",mp[i]+1);
	}
	for(int i=1;i<=q;++i){
		scanf("\n%c %d %d",&c[i],&a[i],&b[i]);
	}
	int x=1,y=1;
	for(int i=1;i<=q;++i){
	    int now=i/k;
		if(query(i%k,now)%2==1){
			c[i]=change(c[i]);
		}
		x+=dx[turn(c[i])]*a[i];
		y+=dy[turn(c[i])]*a[i];
		x=min(max(x,1),n);
		y=min(max(y,1),m);
		if(mp[x][y]=='X'){
			modify(i%k,now+1,1);
			modify(i%k,now+b[i]+1,-1);
		}
	}
	printf("%d %d",x,y);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值