Educational Codeforces Round 115 (Rated for Div. 2) E dp

题目链接

https://codeforces.com/problemset/problem/1598/E

 

题意

有两种形态的楼梯是合法的,其中每种楼梯的每个经过的格子都要是非锁定的,还会问你q个问题,每次改变这个格子的锁定状态,问你当前情况下有多少种楼梯的合法情况

 

我的思路

问题分为两部分:求解初始总方案数,和每次修改带来的总方案数的变化量。

令dp1[i][j]  dp2[i][j] 分别表示从左边转移到当前一格,和从上面转移到当前一格的合法方案数,据此易求出初始状态的方案

分析楼梯的性质知,每次改变只会让一定区域内的合法方案数改变。具体见代码

 

code

#include<bits/stdc++.h>   
#define ll long long
using namespace std;
int n,m,q;
bool locked[1005][1005];
ll dp1[1005][1005],dp2[1005][1005];
int x,y;
ll tot=0;

int main(){
	cin>>n>>m>>q;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			dp1[i][j]=1+dp2[i][j-1];
			dp2[i][j]=1+dp1[i-1][j];
			tot+=dp1[i][j]+dp2[i][j]-1;
		}
	}
//	cout<<tot<<endl;
	
	while(q--){
		scanf("%d%d",&x,&y);
		
		if(locked[x][y]==0){
			locked[x][y]=1;
			
			for(int i=x,j=y+1,k=1;i<=n&&j<=m;k++){
				if(locked[i][j]) break;
				if(k%2){
					dp1[i][j]-=dp2[x][y];
					tot-=dp2[x][y];
					i++;
				}
				else{
					dp2[i][j]-=dp2[x][y];
					tot-=dp2[x][y];
					j++;
				}
			}
			for(int i=x+1,j=y,k=1;i<=n&&j<=m;k++){
				if(locked[i][j]) break;
				if(k%2){
					dp2[i][j]-=dp1[x][y];
					tot-=dp1[x][y];
					j++;
				}
				else{
					dp1[i][j]-=dp1[x][y];
					tot-=dp1[x][y];
					i++;
				}
			}
			
			tot-=(dp1[x][y]+dp2[x][y]-1);
			dp1[x][y]=0;
			dp2[x][y]=0;
		}
		
		else{
			locked[x][y]=0;
			dp1[x][y]=1+dp2[x][y-1];
			dp2[x][y]=1+dp1[x-1][y];
			tot+=dp1[x][y]+dp2[x][y]-1;
			
			for(int i=x,j=y+1,k=1;i<=n&&j<=m;k++){
				if(locked[i][j]) break;
				if(k%2){
					dp1[i][j]+=dp2[x][y];
					tot+=dp2[x][y];
					i++;
				}
				else{
					dp2[i][j]+=dp2[x][y];
					tot+=dp2[x][y];
					j++;
				}
			}
			for(int i=x+1,j=y,k=1;i<=n&&j<=m;k++){
				if(locked[i][j]) break;
				if(k%2){
					dp2[i][j]+=dp1[x][y];
					tot+=dp1[x][y];
					j++;
				}
				else{
					dp1[i][j]+=dp1[x][y];
					tot+=dp1[x][y];
					i++;
				}
			}
			
		}
		printf("%lld\n",tot);
	}
	return 0;
}

 

posted @ 2022-02-16 11:20  starlightlmy  阅读(43)  评论(0)    收藏  举报