2022 NOIP 补题

P8865 [NOIP2022] 种花

注意到 \(F\) 的构造仅仅在 \(C\) 上多了一个横

那么我们统计 \(F\) 的时候统计 \(C\) 即可

考虑预处理对于每一个点向右扩展的合法横边数量 用前缀和实现即可

考虑对 \(C\) 统计 对于 \((a,b)\) 点作为左下角的统计 记录 \(cntl\) 为上面连续(需要隔一行)可达的合法的横边数量

例如我们对下面的东西统计时

00011

01111

00001

00001

在第 \(4\) 行的时候 \(cntl\) 为 \(2\) (因为上一行的边不可达 否则为 \(5\) )

同时 \(cntc\) 为之前可达的所有 \(C\) 图形个数 这样我们累加 \(F\) 即可

所以做完了()

#include<bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define inl inline
#define eb emplace_back
#define endl '\n'
#define pii pair<int,int>
#define mkp make_pair
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int N = 1e3 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;

int read()
{
	int x = 0 , f = 1;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f;
}

int n , m , C , F , f[N][N] , ansc , ansf;
char a[N][N];

signed main ()
{
	ios::sync_with_stdio(false);
	cin.tie(0) , cout.tie(0);
    int T = read() , id = read();
    while ( T -- )
    {
        memset ( f , 0 , sizeof f ) , ansc = ansf = 0;
        n = read() , m = read() , C = read() , F = read();
        for ( int i = 1 ; i <= n ; i ++ )
            for ( int j = 1 ; j <= m ; j ++ )
                cin >> a[i][j];
        for ( int i = 1 ; i <= n ; i ++ )
            for ( int j = m - 1 ; j ; j -- )
            {
                if ( a[i][j] == '1' ) f[i][j] = -1;
                else if ( a[i][j+1] == '0' ) f[i][j] = f[i][j+1] + 1;
            }
        for ( int j = 1 ; j < m ; j ++ )//最后一列显然不用枚举
        {
            int cntl = 0 , cntc = 0;
            for ( int i = 1 ; i <= n ; i ++ )
            {
                if ( f[i][j] == -1 ) { cntl = cntc = 0; continue; }
                ( ansc += f[i][j] * cntl % mod ) %= mod;
                ( ansf += cntc ) %= mod;
                ( cntc += f[i][j] * cntl % mod ) %= mod;
                ( cntl += max ( 0 , f[i-1][j] ) ) %= mod;
            }
        }
        cout << C * ansc % mod << ' ' << F * ansf % mod << endl;
    }
	return 0;
}

P8866 [NOIP2022] 喵了个喵

对于 \(k=2n-2\),显然我们最多是将前 \(n-1\) 个栈全部塞满不同的数,那么我们如果再加进来一个数,是一定可以消除的。

那么我们留栈 \(n\) 为辅助栈。

对于 \(1\) 操作,显然是扫一遍栈来找到一个顶端相同的栈塞进去。

对于 \(2\) 操作,我们将当前数加到栈 \(n\) 中,然后扫一遍找到相同的即可。

否则直接塞进第一个大小 \(< 2\) 的栈即可。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pb pop_back
#define getchar() cin.get()
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
const int M = 2e6 + 5;
const int N = 300 + 5;

int read()
{
	int f = 1 , x = 0;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f;
}

int n , m , k , T;

namespace sub1
{
    int a[M];
    struct node { int op , x , y; };
    vector<node> ans;
    deque<int> sta[N];
    void main()
    {
        while ( T -- )
        {
            n = read() , m = read() , k = read();
            for ( int i = 1 ; i <= n ; i ++ ) sta[i].clear();
            ans.clear();
            for ( int i = 1 ; i <= m ; i ++ )
            {
                a[i] = read();
                int flag = 0;
                for ( int j = 1 ; j < n ; j ++ )
                    if ( sta[j].size() )
                    {
                        if ( sta[j].back() == a[i] ) { ans.eb ( (node) { 1 , j , 0 } ) , sta[j].pb() , flag = 1; break; }
                        else if ( sta[j].front() == a[i] ) { ans.eb ( (node) { 1 , n , 0 } ) , ans.eb ( (node) { 2 , j , n } ) , sta[j].pop_front() , flag = 1; break; }
                    }
                if ( !flag )
                {
                    for ( int j = 1 ; j < n ; j ++ ) if ( sta[j].size() < 2 ) { sta[j].push_back(a[i]); ans.eb ( (node) { 1 , j , 0 } ); break; }
                }
            }
            cout << ans.size() << endl;
            for ( auto p : ans )
            {
                if ( p.op == 1 ) cout << p.op << ' ' << p.x << endl;
                else cout << p.op << ' ' << p.x << ' ' << p.y << endl;
            }
        }
    }
}

namespace sub2
{
    int a[M] , flag;
    struct node { int op , x , y; };
    vector<node> ans , temp;
    deque<int> sta[N];
    int check() 
    {
        // cout << "OK" << sta[1].size() << ' ' << sta[2].size() << endl;
        // cout << "ans" << endl;
        // for ( auto p : ans )
        //     {
        //         if ( p.op == 1 ) cout << p.op << ' ' << p.x << endl;
        //         else cout << p.op << ' ' << p.x << ' ' << p.y << endl;
        //     }
        // cout << "ans" << endl;
        for ( int i = 1 ; i <= n ; i ++ ) if ( sta[i].size() != 0 ) return 0;
        return 1;
    }
    void dfs ( int stp , int lim , int now )
    {
        // cout << stp << ' ' << lim << ' ' << now << endl;
        if ( stp > lim + 1 || now > m + 1 ) return;
        if ( stp == lim + 1 )
        {
            if ( now == m + 1 && check() ) temp = ans , flag = 1;
            return;
        }
        for ( int j = 1 ; j <= n ; j ++ )
            if ( sta[j].size() && sta[j].back() == a[now] )
            {
                ans.eb ( (node) { 1 , j , 0 } ) , sta[j].pb();
                dfs ( stp + 1 , lim , now + 1 );
                ans.pb() , sta[j].eb(a[now]);
                if ( flag ) return;
            }
            else 
            {
                ans.eb ( (node) { 1 , j , 0 } ) , sta[j].eb(a[now]) , dfs ( stp + 1 , lim , now + 1 ) , sta[j].pb() , ans.pb();
                if ( flag ) return;
            }
        for ( int i = 1 ; i <= n ; i ++ )
            for ( int j = i + 1 ; j <= n ; j ++ )
                if ( sta[i].size() && sta[j].size() && sta[i].front() == sta[j].front() )
                {
                    int ti = sta[i].front() , tj = sta[j].front();
                    ans.eb ( (node) { 2 , i , j } ) , sta[i].pop_front() , sta[j].pop_front();
                    dfs ( stp + 1 , lim , now );
                    ans.pb() , sta[i].push_front(ti) , sta[j].push_front(tj);
                    if ( flag ) return;
                }
    }
    void main()
    {
        while ( T -- )
        {
            n = read() , m = read() , k = read();
            for ( int i = 1 ; i <= n ; i ++ ) sta[i].clear();
            temp.clear() , ans.clear();
            for ( int i = 1 ; i <= m ; i ++ ) a[i] = read();
            for ( int i = m ; i <= 2 * m ; i ++ )
            {
                flag = 0 , dfs ( 1 , i , 1 );
                if ( flag ) break;
            }
            cout << temp.size() << endl;
            for ( auto p : temp )
            {
                if ( p.op == 1 ) cout << p.op << ' ' << p.x << endl;
                else cout << p.op << ' ' << p.x << ' ' << p.y << endl;
            }
        }
    }
}


signed main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    T = read();
    if ( T % 10 == 1 ) sub1::main();
    else sub2::main();
    return 0;
}

/*
2
2 4 2
1 2 1 2
2 4 2
1 2 1 2
*/

P8867 [NOIP2022] 建造军营

\(O(2^nm(n+m))\) 的搜索。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pb pop_back
#define getchar() cin.get()
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
const int N = 2e4 + 5;
const int mod = 1e9 + 7;

int read()
{
	int f = 1 , x = 0;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f;
}

int n , m , cnt , ans;

struct edge { int u , v; } e[N];
inl void add ( int u , int v ) { e[++cnt] = { u , v }; }

vector<int> temp;

struct Dsu
{
    int fa[N];
    void init() { for ( int i = 1 ; i <= n ; i ++ ) fa[i] = i; }
    int find ( int x ) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
    void merge ( int u , int v )
    {
        int fu = find(u) , fv = find(v);
        if ( fu != fv ) fa[fu] = fv;
    }
    int pd ()
    {
        int fir = 0;
        for ( int i = 1 ; i <= n ; i ++ ) if ( temp[i] == 1 ) { fir = i; break; }
        for ( int i = 1 ; i <= n ; i ++ ) if ( temp[i] == 1 && find(i) != find(fir) ) return 0;
        return 1;
    }
}D;

void solve ()
{
    int fir = 0;
    for ( int i = 1 ; i <= n ; i ++ ) if ( temp[i] == 1 ) { fir = i; break; }
    if ( !fir ) return;
    int res = 0;
    for ( int i = 1 ; i <= m ; i ++ )
    {
        D.init();
        for ( int j = 1 ; j <= m ; j ++ ) if ( j != i ) D.merge ( e[j].u , e[j].v );
        res += D.pd();
    }
    ( ans += ( 1 << res ) ) %= mod;
}


void dfs ( int stp )
{
    if ( stp == n + 1 ) return solve();
    temp.eb(0) , dfs ( stp + 1 ) , temp.pb();
    temp.eb(1) , dfs ( stp + 1 ) , temp.pb();
}

signed main ()
{
    // ios::sync_with_stdio(false);
    // cin.tie(0) , cout.tie(0);
    n = read() , m = read();
    for ( int i = 1 , u , v ; i <= m ; i ++ ) u = read() , v = read() , add ( u , v );
    temp.eb(0) , dfs ( 1 );
    cout << ans << endl;
    return 0;
}

P8868 [NOIP2022] 比赛

\(8pts\ O(n^4q)\) 太显然了。

考虑优化这个东西。

我们将询问挂到 \(r\) 端点上。

那么枚举 \(r\),设 \(f_i\) 表示的是 \([i,r]\) 之间的答案总和,\(x_i,y_i\) 表示的是 \([i,r]\) 之间的 \(a,b\) 数组最大值。

那么对于新加入的 \(r\),\([1,r]\) 之间的所有 \(x,y,f\) 都可以 \(O(1)\) 维护,处理后统计询问即可,询问的答案为 \(\sum_{j=i}^r f_i\)。

这样的时间复杂度为 \(O(n^2+nq)\)。

#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pb pop_back
#define getchar() cin.get()
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define int unsigned long long
const int N = 3e5 + 5;

int read()
{
	int f = 1 , x = 0;
	char ch = getchar();
	while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
	while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
	return x * f;
}

int n , a[N] , b[N] , q , x[N] , y[N] , ans[N] , f[N];

vector<pii> que[N];

signed main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    int T = read();
    n = read();
    for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
    for ( int i = 1 ; i <= n ; i ++ ) b[i] = read();
    q = read();
    for ( int i = 1 , l , r ; i <= q ; i ++ ) l = read() , r = read() , que[r].eb(l,i);
    for ( int r = 1 ; r <= n ; r ++ )
    {
        for ( int i = 1 ; i <= r ; i ++ ) x[i] = max ( x[i] , a[r] ) , y[i] = max ( y[i] , b[r] ) , f[i] += x[i] * y[i];
        for ( auto p : que[r] )
        {
            int l = p.fi , id = p.se;
            for ( int i = l ; i <= r ; i ++ ) ans[id] += f[i];
        }
    }
    for ( int i = 1 ; i <= q ; i ++ ) cout << ans[i] << endl;
    return 0;
}
posted @ 2023-10-12 09:46  Echo_Long  阅读(28)  评论(0)    收藏  举报