2018-2019 ACM-ICPC, Asia Nakhon Pathom Regional Contest 部分题解

比赛链接

Problem A Flying Squirrel

[l,r]区间最大值的下标是id,那么区间被划分为了左区间[l,id-1]和右区间[id+1,r]。左右区间不可达,相当于是划分。

如果每个区间内只有一个最大值,那么这其实是一个类似于线段树的东西。

但是因为可能有多个相同的最大值,所以其实是个分层图。不严格地说,每个节点既可以有多个父亲,又可以有多个儿子。

每个区间内相同的最大值深度相同,进行划分即可。

y=0时,答案是x子树内部的深度最大值减去x的深度。

y\neq 0时,如果x,y之间没有大于等于h[x]的柱子,也就是x可以到达y。那么答案就是两者深度差的绝对值。

#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1e5 + 10 ;
int n , q ;
int a[maxn] ;  //区间最大值对应的下标
int st[maxn][25] ;
void init() 
{
   for(int i = 1 ; i <= n ; i ++) st[i][0] = i ; 
   for(int j = 1 ; j <= 20 ; j ++)
   for(int i = 1 ; i + (1 << j) - 1 <= n ; i ++)
     if(a[st[i][j - 1]] >= a[st[i + (1 << (j - 1))][j - 1]])
       st[i][j] = st[i][j - 1] ;
     else  st[i][j] = st[i + (1 << (j - 1))][j - 1] ; 
}
int query(int l,int r)
{ 
   int len = log2(r - l + 1) ;
   if(a[st[l][len]] >= a[st[r - (1 << len) + 1][len]])  return st[l][len] ;
   else  return st[r - (1 << len) + 1][len] ;
}
int ans[maxn] ;
int dep[maxn] ;
vector<int> p ;
void dfs(int l , int r , int val , int d)
{
    if(l > r)  return ;
    int id = query(l , r) ;
    if(a[id] != val)  return ;
    p.push_back(id) ;
    dep[id] = d ;
    dfs(l , id - 1 , val , d) ;
    dfs(id + 1 , r , val , d) ;
}
int solve(int l , int r , int d)
{
    int res = d ;
    int id = query(l , r) ;
    p.clear() ;
    dfs(l , r , a[id] , d) ;
    vector<int> pos = p ;
    int siz = pos.size() ;
    if(dep[l] == 0)
    {
        int t = pos[0] ;
        int tmp = solve(l , t - 1 , d + 1) ;
        res = max(res , tmp) ;
        ans[t] = max(ans[t] , tmp - d) ;
    }
    if(dep[r] == 0)
    {
        int t = pos[siz - 1] ;
        int tmp = solve(t + 1 , r , d + 1) ;
        res = max(res , tmp) ;
        ans[t] = max(ans[t] , tmp - d) ;
    }
    for(int i = 0 ; i + 1 < siz ; i ++)
    {
        int now = pos[i] ;
        int nxt = pos[i + 1] ;
        if(now + 1 == nxt)  continue ;
        int tmp = solve(now + 1 , nxt - 1 , d + 1) ;
        res = max(res , tmp) ;
        ans[now] = max(ans[now] , tmp - d) ;
        ans[nxt] = max(ans[nxt] , tmp - d) ;
    }
    return res ;
}
void init2()
{
    solve(1 , n , 1) ;
}
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    cin >> n >> q ;
    for(int i = 1 ; i <= n ; i ++)  cin >> a[i] ;
    init() ;
    init2() ;
    //for(int i = 1 ; i <= n ; i ++)  cout << i << ' ' << dep[i] << ' ' << ans[i] << '\n' ;
    while(q --)
    {
        int l , r ;
        cin >> l >> r ;
        if(r == 0)  cout << ans[l] << '\n' ;
        else
        {
            if(dep[l] > dep[r])  swap(l , r) ;
            if(dep[l] == dep[r])  cout << "0\n" ;
            else if(l < r)
            {
                int id = query(l + 1 , r) ;
                if(dep[id] <= dep[l])  cout << "0\n" ;
                else  cout << dep[r] - dep[l] << '\n' ;
            }
            else
            {
                int id = query(r , l - 1) ;
                if(dep[id] <= dep[l])  cout << "0\n" ;
                else  cout << dep[r] - dep[l] << '\n' ;
            }
        }
    }
    return 0 ;
}

 

Problem B Grid Coloring

留坑。

 

Problem C Evolution Game

按照horns的大小升序排列。

j<i且两者的eyes数量不超过wdp[i]=max(dp[i],dp[j]+1)

#include<bits/stdc++.h>
using namespace std ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n , w ;
    cin >> n >> w ;
    vector<pair<int , int>> v(n + 1) ;
    for(int i = 1 ; i <= n ; i ++)
    {
        int h ;
        cin >> h ;
        v[i] = {h , i} ;
    }
    sort(v.begin() + 1 , v.end()) ;
    vector<int> dp(n + 1 , 0) ;
    for(int i = 2 ; i <= n ; i ++)
        for(int j = 1 ; j < i ; j ++)
            if(abs(v[j].second - v[i].second) <= w && v[j].first < v[i].first)
                dp[i] = max(dp[i] , dp[j] + 1) ;
    cout << *max_element(dp.begin() + 1 , dp.end()) ;
    return 0 ;
}

 

Problem D Bus Stop

从左往右扫,扫到x时,如果[x-10,x+10]的范围内没有stops,那么在x+10的位置安装一个stops

#include<bits/stdc++.h>
using namespace std ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int T ;
    cin >> T ;
    while(T --)
    {
        int n ;
        cin >> n ;
        vector<int> a(n + 1) ;
        for(int i = 1 ; i <= n ; i ++)  cin >> a[i] ;
        int lst = -100000 ;
        int ans = 0 ;
        for(int i = 1 ; i <= n ; i ++)
        {
            if(abs(a[i] - lst) <= 10)  continue ;
            else  lst = a[i] + 10 , ans ++ ;
        }
        cout << ans << '\n' ;
    }
    return 0 ;
}

 

Problem E How many groups

本来写了200多行的分类讨论,虽然过了,不过很不爽。

看了别人代码发现是个简单dp,感觉失去了一个亿。

分类讨论。

#include<bits/stdc++.h>
using namespace std ;
int n ;
int a[105] ;
int l[105] ;
int r[105] ;
int c[2] = {-1 , 1} ;
int d[4] = {-1 , 1 , 0 , 0} ;
int e[4] = {0 , 0 , -1 , 1} ;
int cal1(int i)
{
    int res = 1 ;
    if(i - 1 >= 1 && abs(a[i - 1] - a[i]) <= 2)  res += ((i - 1) - l[i - 1] + 1) ;
    if(i + 1 <= n && abs(a[i + 1] - a[i]) <= 2)  res += (r[i + 1] - (i + 1) + 1) ;
    return res ;
}
int cal2(int i , int j)
{
    if(abs(a[i] - a[j]) > 2)  return 0 ;
    int res = 2 ;
    if(i - 1 >= 1 && abs(a[i - 1] - a[i]) <= 2)  res += ((i - 1) - l[i - 1] + 1) ;
    if(j + 1 <= n && abs(a[j + 1] - a[j]) <= 2)  res += (r[j + 1] - (j + 1) + 1) ;
    return res ;
}
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int T ;
    cin >> T ;
    for(int cas = 1 ; cas <= T ; cas ++)
    {
        cout << "Case " << cas << ": " ;
        cin >> n ;
        for(int i = 1 ; i <= n ; i ++)  cin >> a[i] ;
        sort(a + 1 , a + n + 1) ;
        int ans = 0 ;
        for(int i = 1 ; i <= n ; i ++)
        {
            int j = i ;
            while(j + 1 <= n && a[j + 1] - a[j] <= 2)  j ++ ;
            for(int k = i ; k <= j ; k ++)  l[k] = i , r[k] = j ;
            ans = max(ans , j - i + 1) ;
            i = j ;
        }
        for(int i = 1 ; i <= n ; i ++)  
        {
            int tmp = a[i] ;
            for(int j = 0 ; j < 2 ; j ++)
            {
                a[i] = tmp + c[j] ;
                ans = max(ans , cal1(i)) ;
            }
            a[i] = tmp ;
        }
        for(int i = 1 ; i <= n - 1 ; i ++)
        {
            int tmp1 = a[i] ;
            int tmp2 = a[i + 1] ;
            for(int j = 0 ; j < 2 ; j ++)
                for(int k = 0 ; k < 2 ; k ++)
                {
                    a[i] = tmp1 + c[j] ;
                    a[i + 1] = tmp2 + c[k] ;
                    ans = max(ans , cal2(i , i + 1)) ; 
                }
            a[i] = tmp1 ;
            a[i + 1] = tmp2 ;
        }
        //cout << ans << '\n' ;
        for(int i = 1 ; i <= n ; i ++)
        {
            int res = 1 ;
            a[i] ++ ;
            if(i + 1 <= n)
            {
                if(i - 1 >= 1 && abs(a[i] - a[i - 1]) <= 2)  res += (i - 1) - l[i - 1] + 1 ;
                ans = max(ans , res) ;
                if(abs(a[i] - a[i + 1]) <= 2)
                {
                    res += r[i + 1] - (i + 1) + 1 ;
                    ans = max(ans , res) ;
                    int nxt = r[i + 1] ;
                    //cout << nxt << '\n' ;
                    if(nxt + 1 <= n)
                    {
                        int tmp1 = a[nxt] ;
                        int tmp2 = a[nxt + 1] ;
                        for(int j = 0 ; j < 4 ; j ++)
                            {
                                a[nxt] = tmp1 + d[j] ;
                                a[nxt + 1] = tmp2 + e[j] ;
                                int tt = res ;
                                if(abs(a[nxt] - a[nxt + 1]) <= 2)
                                {
                                    if(abs(a[nxt] - a[nxt - 1]) <= 2)
                                    {
                                        tt ++ ;
                                        //cout << res << '\n' ;
                                        if(nxt + 2 <= n && abs(a[nxt + 1] - a[nxt + 2]) <= 2)
                                        {
                                            tt += r[nxt + 2] - (nxt + 2) + 1 ;
                                        }
                                        ans = max(ans , tt) ;
                                    }
                                }
                            }
                        a[nxt] = tmp1 ;
                        a[nxt + 1] = tmp2 ;
                    }
                }
            }
            a[i] -- ;
            
            res = 1 ;
            a[i] -- ;
            if(i + 1 <= n)
            {
                if(i - 1 >= 1 && abs(a[i] - a[i - 1]) <= 2)  res += (i - 1) - l[i - 1] + 1 ;
                ans = max(ans , res) ;
                if(abs(a[i] - a[i + 1]) <= 2)
                {
                    res += r[i + 1] - (i + 1) + 1 ;
                    ans = max(ans , res) ;
                    int nxt = r[i + 1] ;
                    //cout << nxt << '\n' ;
                    if(nxt + 1 <= n)
                    {
                        int tmp1 = a[nxt] ;
                        int tmp2 = a[nxt + 1] ;
                        for(int j = 0 ; j < 4 ; j ++)
                            {
                                a[nxt] = tmp1 + d[j] ;
                                a[nxt + 1] = tmp2 + e[j] ;
                                int tt = res ;
                                if(abs(a[nxt] - a[nxt + 1]) <= 2)
                                {
                                    if(abs(a[nxt] - a[nxt - 1]) <= 2)
                                    {
                                        tt ++ ;
                                        //cout << res << '\n' ;
                                        if(nxt + 2 <= n && abs(a[nxt + 1] - a[nxt + 2]) <= 2)
                                        {
                                            tt += r[nxt + 2] - (nxt + 2) + 1 ;
                                        }
                                        ans = max(ans , tt) ;
                                    }
                                }
                            }
                        a[nxt] = tmp1 ;
                        a[nxt + 1] = tmp2 ;
                    }
                }
            }
            a[i] ++ ;
        }
        //cout << ans << '\n' ;
        for(int i = 1 ; i <= n ; i ++)
        {
            a[i] -- ;
            int res = 1 ;
            if(i - 1 >= 1)
            {
                if(i + 1 <= n && abs(a[i] - a[i + 1]) <= 2)  res += r[i + 1] - (i + 1) + 1 ;
                ans = max(ans , res) ;
                if(abs(a[i] - a[i - 1]) <= 2)
                {
                    res += (i - 1) - l[i - 1] + 1 ;
                    ans = max(ans , res) ;
                    int nxt = l[i - 1] ;
                    if(nxt - 1 >= 1)
                    {
                        int tmp1 = a[nxt] ;
                        int tmp2 = a[nxt - 1] ;
                        for(int j = 0 ; j < 4 ; j ++)
                            {
                                int tt = res ;
                                a[nxt] = tmp1 + d[j] ;
                                a[nxt - 1] = tmp2 + e[j] ;
                                if(abs(a[nxt] - a[nxt - 1]) <= 2)
                                {
                                    if(abs(a[nxt] - a[nxt + 1]) <= 2)
                                    {
                                        tt ++ ;
                                        if(nxt - 2 >= 1 && abs(a[nxt - 1] - a[nxt - 2]) <= 2)
                                        {
                                            tt += (nxt - 2) - l[nxt - 2] + 1 ;
                                        }
                                        ans = max(ans , tt) ;
                                    }
                                }
                            }
                        a[nxt] = tmp1 ;
                        a[nxt - 1] = tmp2 ;
                    }
                }
            }
            a[i] ++ ;
        
            a[i] ++ ;
            res = 1 ;
            if(i - 1 >= 1)
            {
                if(i + 1 <= n && abs(a[i] - a[i + 1]) <= 2)  res += r[i + 1] - (i + 1) + 1 ;
                ans = max(ans , res) ;
                if(abs(a[i] - a[i - 1]) <= 2)
                {
                    res += (i - 1) - l[i - 1] + 1 ;
                    ans = max(ans , res) ;
                    int nxt = l[i - 1] ;
                    if(nxt - 1 >= 1)
                    {
                        int tmp1 = a[nxt] ;
                        int tmp2 = a[nxt - 1] ;
                        for(int j = 0 ; j < 4 ; j ++)
                            {
                                int tt = res ;
                                a[nxt] = tmp1 + d[j] ;
                                a[nxt - 1] = tmp2 + e[j] ;
                                if(abs(a[nxt] - a[nxt - 1]) <= 2)
                                {
                                    if(abs(a[nxt] - a[nxt + 1]) <= 2)
                                    {
                                        tt ++ ;
                                        if(nxt - 2 >= 1 && abs(a[nxt - 1] - a[nxt - 2]) <= 2)
                                        {
                                            tt += (nxt - 2) - l[nxt - 2] + 1 ;
                                        }
                                        ans = max(ans , tt) ;
                                    }
                                }
                            }
                        a[nxt] = tmp1 ;
                        a[nxt - 1] = tmp2 ;
                    }
                }
            }
            a[i] -- ;
        }
        cout << ans << '\n' ;
    }
    return 0 ;
}

 

dp[i][j][k]表示前i个数修改了j次且第i个数是a[i]+k-1的以i为右端点的最大连续段长度。

#include<bits/stdc++.h>
using namespace std ;
int n , a[105] ;
int dp[105][3][3] ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int T ;
    cin >> T ;
    for(int cas = 1 ; cas <= T ; cas ++)
    {
        cout << "Case " << cas << ": " ;
        cin >> n ;
        for(int i = 1 ; i <= n ; i ++)  cin >> a[i] ;
        sort(a + 1 , a + n + 1) ;
        for(int i = 0 ; i <= n ; i ++)  
            for(int j = 0 ; j <= 2 ; j ++)  
                for(int k = 0 ; k <= 2 ; k ++)
                    dp[i][j][k] = -1e9 ;
        int fix = 1 ;
        for(int i = 1 ; i <= n ; i ++)
        {
            dp[i][0][fix + 0] = 1 ;
            dp[i][1][fix - 1] = 1 ;
            dp[i][1][fix + 1] = 1 ;
        }
        for(int i = 1 ; i < n ; i ++)  
            for(int j = 0 ; j <= 2 ; j ++)
                for(int k = 0 ; k <= 2 ; k ++)
                    for(int p = j ; p <= 2 ; p ++)
                        for(int t = 0 ; t <= 2 ; t ++)
                        {
                            if(dp[i][j][k] < 0)  continue ;
                            int now = a[i] + k - fix ;
                            int nxt = a[i + 1] + t - fix ;
                            if(abs(now - nxt) <= 2 && (j + abs(t - fix)) == p)
                            {
                                dp[i + 1][p][t] = max(dp[i + 1][p][t] , dp[i][j][k] + 1) ;
                            }
                        }
        int ans = 0 ;
        for(int i = 1 ; i <= n ; i ++)
            for(int j = 0 ; j <= 2 ; j ++)
                for(int k = 0 ; k <= 2 ; k ++)
                    ans = max(ans , dp[i][j][k]) ;
        cout << ans << '\n' ;
    }
    return 0 ;
}

 

Problem F Lucky Pascal Triangle

求满足n \leq N,m \leq N,7 \mid \binom{n}{m}nm的对数

库默尔定理:\binom{n+m}{m}中p的幂次为n+m在p进制下进位次数,p为质数

题目可以转化为求n-m和m在7进制下产生了进位的对数

数位dp:f[i][j][lim][d]表示从高到低考虑到第i位,已经产生了j个进位,是否有大小限制,是否强制下一位产生进位的方案数

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int p = 7, mod = 1e9 + 7;
int kas;
ll n;
int a[25], len;
int f[25][2][2][2];
inline void Add(int &x, int y) { x += y; if(x>=mod) x -= mod; }
void change(ll n)
{
    len = 0;
    while(n)
    {
        a[len++] = n%p;
        n /= p; 
    }
}
int count(int x)
{
    if(x<p) return (1ll*(x+1)*(x+2)>>1)%mod;
    x = 2*p - 2 - x;
    return (1ll*p*p-(1ll*(x)*(x+1)>>1))%mod;
}
int cal(int l, int r) { return (count(r)-count(l-1)+mod)%mod; }
void solve()
{
    scanf("%lld", &n);
    change(n);
    for(int i=0; i<=len; i++) memset(f[i], 0, sizeof(f[i]));
    f[len][0][1][0] = 1;
    for(int i=len; i; i--)
        for(int j=0; j<2; j++)
            for(int lim=0; lim<2; lim++)
                for(int d=0; d<2; d++) if(f[i][j][lim][d])
                    for(int nxtd=0; nxtd<2; nxtd++)
                    {
                        int l = d*p - nxtd, r = (lim ? a[i-1] : p-1) + l;
                        if(lim) Add(f[i-1][j|nxtd][0][nxtd], 1ll*f[i][j][1][d]*cal(l, r-1)%mod), Add(f[i-1][j|nxtd][1][nxtd], 1ll*f[i][j][1][d]*cal(r, r)%mod);
                        else Add(f[i-1][j|nxtd][0][nxtd], 1ll*f[i][j][0][d]*cal(l, r)%mod);
                    }
    int ans = (f[0][1][0][0] + f[0][1][1][0])%mod;
    printf("Case %d: %d\n", ++kas, ans);
}
int main()
{
    int _; scanf("%d", &_);
    while(_--) solve();
    return 0;
}

 

Problem G Communication

题面的英语写的过于上等。没说message是可传递的,然后写了个并查集果然WA了。

反应过来如果可以传递就是一个SCC,贴个板子就过了。

#include<bits/stdc++.h>
using namespace std ;
const int maxn = 200 + 10 ;
const int maxm = 10000 + 10 ;
int n ;
struct Link
{
    int num , head[maxn] ;
    struct Edge
    {
        int v , next ;
    } edge[maxm << 1] ;
    void init()
    {
        num = 0 ;
        memset(head , -1 , sizeof(head)) ;
    }
    void add_edge(int u , int v)
    {
        edge[num].v = v ;
        edge[num].next = head[u] ;
        head[u] = num ++ ;  
    } 
} link ;
struct Tarjan
{
    int cnt , scc_num , lay ;
    int low[maxn] , dfn[maxn] , belong[maxn] ; 
    int st[maxn] , s[maxn] ;
    bool vis[maxn] ;
    void init()
    {
        cnt = scc_num = lay = 0 ;
        memset(vis , 0 , sizeof(vis)) ;
        memset(low , 0 , sizeof(low)) ;
        memset(dfn , 0 , sizeof(dfn)) ;
    }
    void dfs(int k)
    {
        vis[k] = 1 ;
        low[k] = dfn[k] = ++ lay ;
        st[++ cnt] = k ;
        for(int i = link.head[k] ; i != -1 ; i = link.edge[i].next)
        {
            int v = link.edge[i].v ;
            if(dfn[v] == 0)
            {
                dfs(v) ;
                low[k] = min(low[k] , low[v]) ;
            }
            else if(vis[v])
            low[k] = min(low[k] , dfn[v]) ;
        }
        if(dfn[k] == low[k])
        {
            ++ scc_num ;
            do
            {
                belong[st[cnt]] = scc_num ;
                vis[st[cnt]] = 0 ;
                cnt -- ;
            } while(st[cnt + 1] != k) ;
        }
    }
    void cal()
    {
        for(int i = 1 ; i <= n ; i ++)
        if(dfn[i] == 0)  dfs(i) ;
    }
} tarjan ; 
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int T ;
    cin >> T ;
    while(T --)
    {
        cin >> n ;
        link.init() ;
        tarjan.init() ;
        int e ;
        cin >> e ;
        for(int i = 1 ; i <= e ; i ++)
        {
            int u , v ;
            cin >> u >> v ;
            u ++ ;
            v ++ ;
            link.add_edge(u , v) ;
        }
        tarjan.cal() ;
        cout << tarjan.scc_num << '\n' ;
    }
    return 0 ;
}

 

Problem H As rich as Crassus

留坑。

 

Problem I Bowabowaukulipukuli

留坑。

 

Problem J Floating-Point Hazard

需要看出来这是求导定义式的分子。

f(x)=x^{\frac{1}{3}},求导后得到f^{'}(x)

答案是\sum f^{'}(i)*(10^{-15})

#include<bits/stdc++.h>
using namespace std ;
#define ld long double
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    while(1)
    {
        int l , r ;
        scanf("%d%d" , &l , &r) ;
        if(l == 0 && r == 0)  break ;
        ld ans = 0 ;
        for(int i = l ; i <= r ; i ++)  ans += pow(i , -2.0 / 3.0) ;
        ans /= 3.0 ;
        int res = 15 ;
        while(ans >= 10.0)  ans /= 10 , res -- ;
        while(ans < 1.0)  ans *= 10 , res ++ ;
        printf("%.5LfE-" , ans) ;
        printf("%03d\n" , res) ;
    }
    return 0 ;
}

 

Problem K The Stream of Corning 2

裸的第k大。

#include <bits/stdc++.h>
#define all(x) begin(x), end(x)
using namespace std;
const int N = 1e5 + 5;
const int MAXSIZE = 1 << 20;
char buf[MAXSIZE], *p1, *p2;
inline char gc() { return (p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXSIZE,stdin),p1==p2) ? EOF : *p1++); }
inline void read(int& t)
{
    t = 0; char c = gc();
    while(c>'9'||c<'0') c = gc();
    while(c>='0'&&c<='9') t = t*10 + c - 48, c = gc();
}
bool qry[N];
int kas;
int n, ans[N];
struct Event
{
    int t, v, op;
    bool operator < (const Event& oth) { return t==oth.t ? op<oth.op : t<oth.t; }
}e[N<<1];
struct seg
{
    int l, r, cnt;
}t[N<<2];
void up(int p) { t[p].cnt = t[p<<1].cnt + t[p<<1|1].cnt; }
void build(int p, int l, int r)
{
    t[p].l = l, t[p].r = r, t[p].cnt = 0;
    if(l==r) return;
    int mid = (l+r)>>1;
    build(p<<1, l, mid); build(p<<1|1, mid+1, r);
}
void upd(int p, int x, int v)
{
    int l = t[p].l, r = t[p].r;
    if(l==r) 
    {
        t[p].cnt += v;
        return;
    }
    int mid = (l+r) >> 1;
    if(x<=mid) upd(p<<1, x, v);
    else upd(p<<1|1, x, v);
    up(p);
}
int ask(int p, int k) 
{
    int l = t[p].l, r = t[p].r;
    if(l==r) return t[p].cnt>=k ? l : -1;
    if(t[p<<1].cnt>=k) return ask(p<<1, k);
    else return ask(p<<1|1, k-t[p<<1].cnt);
}
void solve()
{
    read(n);
    int m = 0;
    vector<int> lsh;
    auto getid = [&](int x) { return lower_bound(all(lsh), x) - begin(lsh) + 1; };
    for(int i=1; i<=n; i++)
    {
        qry[i] = 0;
        int op; read(op);
        if(op==1)
        {
            int l, v, r; read(l), read(v), read(r);
            e[++m] = {l, v, 1};
            e[++m] = {r+1, v, -1};
            lsh.push_back(v);
        }
        else
        {
            qry[i] = 1;
            int t, k; read(t), read(k);
            e[++m] = {t, k, i+1};
        }
    }
    sort(all(lsh));
    lsh.resize(unique(all(lsh)) - begin(lsh));
    build(1, 1, (int)lsh.size());
    sort(e+1, e+m+1);
    for(int i=1; i<=m; i++)
    {
        if(e[i].op<=1) upd(1, getid(e[i].v), e[i].op);
        else ans[e[i].op-1] = ask(1, e[i].v);
    }
    printf("Case %d:\n", ++kas);
    for(int i=1; i<=n; i++) 
        if(qry[i]) 
        {
            if(ans[i]==-1) puts("-1");
            else printf("%d\n", lsh[ans[i]-1]);
        }
}
int main()
{
    int _; read(_);
    while(_--) solve();
    return 0;
}

 

Problem L Largest Allowed Area

看作二维平面上的点,在斜率是-1的直线上进行双指针扫描,以L作为左上角的点,R作为右下角的点。前缀和预处理后可以O(1)判断正方形内1的个数。

不过这题卡常,需要快读。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 5, inf = 1e9;
int n, m;
int a[N][N], r[N][N], s[N][N];
int qry(int x1, int y1, int x2, int y2) { return s[x2][y2]+s[x1-1][y1-1]-s[x2][y1-1]-s[x1-1][y2]; }
inline void read(int& t)
{
    t = 0; 
    char c = getchar();
    while(c>'9'||c<'0') c = getchar();
    while(c>='0'&&c<='9') t = t*10 + c - 48, c = getchar();
}
void solve()
{
    read(n), read(m);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=m; j++) read(a[i][j]), s[i][j] = s[i][j-1]+s[i-1][j]-s[i-1][j-1]+a[i][j];
    for(int i=0; i<=n; i++)
        for(int j=0; j<=m; j++) r[i][j] = i;
    int ans = 0;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            int rgt = r[i-1][j-1];
            while(rgt+1<=i && qry(rgt+1, rgt+1+j-i, i, j)>1) rgt++;
            ans = max(ans, i-rgt);
            r[i][j] = rgt;
        }
    }
    printf("%d\n", ans);
}
int main()
{
    int _; read(_);
    while(_--) solve(); 
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值