2022 NOIP 补题

P8865 [NOIP2022] 种花

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

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

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

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

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

00011

01111

00001

00001

在第 4 行的时候 cntl2 (因为上一行的边不可达 否则为 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=2n2,显然我们最多是将前 n1 个栈全部塞满不同的数,那么我们如果再加进来一个数,是一定可以消除的。

那么我们留栈 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(2nm(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(n4q) 太显然了。

考虑优化这个东西。

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

那么枚举 r,设 fi 表示的是 [i,r] 之间的答案总和,xi,yi 表示的是 [i,r] 之间的 a,b 数组最大值。

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

这样的时间复杂度为 O(n2+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 @   Echo_Long  阅读(12)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示