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  阅读(19)  评论(0)    收藏  举报