Codeforces Round 878 (Div. 3) F. Railguns

Codeforces Round 878 (Div. 3) F. Railguns

  • 题意


T e m a Tema Tema n ⋅ m n·m nm 的网格内要从 ( 0 , 0 ) (0,0) (0,0) 走到 ( n , m ) (n,m) (n,m)。第 0 0 0 秒末 T e m a Tema Tema 位于 ( 0 , 0 ) (0,0) (0,0)

​ 假设 T e m a Tema Tema 正位于 ( i , j ) (i,j) (i,j),每秒他可以做三种行动:

​ ①该秒末移动到 ( i + 1 , j ) (i+1,j) (i+1,j)

​ ②该秒末移动到 ( i , j + 1 ) (i,j+1) (i,j+1)

​ ③该秒末停留在 ( i , j ) (i,j) (i,j)

​ 机器人会发射 r r r 次激光炮以阻挠他前进,具体为在第 t t t 秒,向第 x x x 行或第 x x x 列发射激光炮,一整列或一整行都会受到炮击。若 T e m a Tema Tema 在第 t t t 秒末还停留在被炮击的单元格内则会被击毁。求 T e m a Tema Tema ( 0 , 0 ) (0,0) (0,0) 到达 ( n , m ) (n,m) (n,m) 的最短时间,若无法抵达,则输出 − 1 -1 1

r r r 次炮击格式为 t , d , c o o r d t,d,coord t,d,coord t t t 表示炮击发生的时间, d d d 表示炮击方式( d = 1 d=1 d=1 时攻击一整行, d = 2 d=2 d=2时攻击一整列), c o o r d coord coord 表示攻击的是具体哪一行/列。

  • 分析


T e m a Tema Tema ( i , j ) (i,j) (i,j) 处会出现的时间在 [ i + j , i + j + r ] [i+j,i+j+r] [i+j,i+j+r] 范围内。

​ 如下情况, T e m a Tema Tema ( 1 , 1 ) (1,1) (1,1) 处出现的时间取到最大值 i + j + r i+j+r i+j+r

在这里插入图片描述

​ 所以,设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k] 表示 T e m a Tema Tema 在时间 i + j + k i+j+k i+j+k 时能否到达 ( i , j ) (i,j) (i,j)

​ 有转移方程
{ d p [ i ] [ j ] [ k ] = d p [ i − 1 ] [ j ] [ k ] ∣ d p [ i ] [ j ] [ k ] i > 0 d p [ i ] [ j ] [ k ] = d p [ i ] [ j − 1 ] [ k ] ∣ d p [ i ] [ j ] [ k ] j > 0 d p [ i ] [ j ] [ k ] = d p [ i ] [ j ] [ k − 1 ] ∣ d p [ i ] [ j ] [ k ] i + j + k 这个时间没有被炮击 \begin{cases}dp[i][j][k]=dp[i-1][j][k]|dp[i][j][k]&&i>0\\dp[i][j][k]=dp[i][j-1][k]|dp[i][j][k]&&j>0\\dp[i][j][k]=dp[i][j][k-1]|dp[i][j][k]&&i+j+k这个时间没有被炮击\end{cases} dp[i][j][k]=dp[i1][j][k]dp[i][j][k]dp[i][j][k]=dp[i][j1][k]dp[i][j][k]dp[i][j][k]=dp[i][j][k1]dp[i][j][k]i>0j>0i+j+k这个时间没有被炮击

​ 检查某个时间某行/列是否被炮击,用 s e t set set 维护每行/列被炮击的时间然后二分查找即可。

  • 代码


#include<bits/stdc++.h>
using namespace std ;
#define ll long long
#define double long double
const ll N = 1e6+9 ;
const ll INF = 1e17 ;
const ll mod = 1e9+7 ;
//const double pi = acos(-1) ;
const double eps = 1e-7 ;
ll gcd( ll a , ll b ){ return a == 0 ? b : gcd( b%a , a ) ; }
ll lcm( ll a , ll b ){ return (a/gcd(a,b))*b ; }
ll Abs( ll x ){ return x < 0 ? -x : x ; }
ll n , m , r ;
void solve(){
    cin >> n >> m >> r ;
    vector<set<ll>>a(n+1),b(m+1) ;
    vector<vector<vector<bool>>>dp(n+1,vector<vector<bool>>(m+1,vector<bool>(r+10,0))) ;
    for( int i = 1 ; i <= r ; i ++ ){
        ll t , d , pos ; cin >> t >> d >> pos ;
        if( d == 2 ) b[pos].insert(t) ;
        if( d == 1 ) a[pos].insert(t) ;
    }

    ll up = min( ( a[0].lower_bound(0+1) == a[0].end() ? r+1 : *a[0].lower_bound(0+1) ) ,
                 ( b[0].lower_bound(0+1) == b[0].end() ? r+1 : *b[0].lower_bound(0+1) )
                ) ;
    //up:大于等于该时间点被炮击的时间,若不存在则取r+1

    for( int i = 0 ; i <= up ; i ++ ) dp[0][0][i] = 1 ;

    for( int i = 0 ; i <= n ; i ++ )
        for( int j = 0 ; j <= m ; j ++ )
            for( int k = 0 ; k <= r ; k ++ ){

                up = min( ( a[i].lower_bound(i+j+k) == a[i].end() ? r+1 : *a[i].lower_bound(i+j+k)-i-j ) ,
                          ( b[j].lower_bound(i+j+k) == b[j].end() ? r+1 : *b[j].lower_bound(i+j+k)-i-j )
                        ) ;

                if( up == k ) dp[i][j][k] = 0 ;
                else{
                    if( i > 0 ) dp[i][j][k] = dp[i][j][k] | dp[i-1][j][k] ;
                    if( j > 0 ) dp[i][j][k] = dp[i][j][k] | dp[i][j-1][k] ;
                    if( k > 0 ) dp[i][j][k] = dp[i][j][k] | dp[i][j][k-1] ;
                }
    }

    for( int i = 0 ; i <= r ; i++ ) if( dp[n][m][i] ){
        cout << n+m+i << "\n" ; return ;
    }
    cout << "-1\n" ; return ;
}
int main(){
    ios::sync_with_stdio(false) ; cin.tie(0) ; cout.tie(0) ;
    ll tt = 1 ; cin >> tt ;
    while( tt-- ) solve() ;
    return 0 ;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值