2021 NOIP 补题

P7960 [NOIP2021] 报数

这就是你游 \(noip2021\) \(T1\) 是罢。

简单筛一筛就好了。

注意记录 \(nxt\) 数组表示当前点的下一个数是什么,否则会超时,而且提前预处理质数要到 \(1e7+10\)

#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 = 1e7 + 15;
const int maxn = N - 5;
const int mod = 998244353;

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 , iskey[N] , nxt[N];

int check ( int x )
{
    while ( x )
    {
        if ( x % 10 == 7 ) return 1;
        x /= 10;
    }
    return 0;
}

void init()
{
    int lst = 0;
    for ( int i = 1 ; i <= maxn ; i ++ )
    {
        if ( iskey[i] ) continue;
        if ( check(i) )
        {
            iskey[i] = 1;
            for ( int j = i ; j <= maxn ; j += i ) iskey[j] = 1;
        }
        else nxt[lst] = i , lst = i;
    }
}

signed main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    init();
    int T = read();
    while ( T -- )
    {
        int x = read();
        if ( iskey[x] ) cout << -1 << endl;
        else cout << nxt[x] << endl;
    }
    return 0;
}

P7961 [NOIP2021] 数列

暴搜太显然了,这里给出 \(50pts\) 记忆化优化爆搜。

记录 \(f_{i,j}\) 表示前 \(i\) 个数,凑出来的数为 \(j\) 的方案数,枚举当前这个数选 \([0,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
#define int long long
const int N = 30 + 5;
const int M = 30 * ( 1 << 12 ) + 5;
const int mod = 998244353;

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 , v[N] , f[N][M];

int dfs ( int stp , int sum )
{
    if ( stp == n + 1 ) return __builtin_popcount(sum) <= k;
    if ( f[stp][sum] != -1 ) return f[stp][sum];
    int res = 0;
    for ( int i = 0 ; i <= m ; i ++ ) ( res += dfs ( stp + 1 , sum + ( 1 << i ) ) * v[i] % mod ) %= mod;
    return f[stp][sum] = res;
}

signed main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    memset ( f , -1 , sizeof f );
    n = read() , m = read() , k = read();
    for ( int i = 0 ; i <= m ; i ++ ) v[i] = read();
    cout << dfs ( 1 , 0 ) << endl;
    return 0;
}

P7962 [NOIP2021] 方差

搜索中,状态边界的设计可以是当前的操作状态是否被访问过了。

特别注意,这样设计边界状态之后,不需要回溯时取消对当前状态的标记(\(12\rightarrow24\))。

这里加了卡时是 \(32pts\)

#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 long long
const int N = 1e4 + 5;
const int base = 131;
const int mod = 1e7 + 19;
const int inf = 0x3f3f3f3f;

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 , ans = inf;
int a[N] , temp[N];

clock_t st;
bitset<mod> vis;

int check ()
{
    int sum = 0 , res = 0;
    for ( int i = 1 ; i <= n ; i ++ ) sum += temp[i];
    for ( int i = 1 ; i <= n ; i ++ ) res += ( n * temp[i] - sum ) * ( n * temp[i] - sum );
    return res / n;
}

int hashh ( int tmp[] )
{
    int res = 0;
    for ( int i = 2 ; i < n ; i ++ ) res = ( res * base % mod + tmp[i] ) % mod;
    return res;
}

void dfs ()
{
    if ( ( clock() - st ) * 1e3 / CLOCKS_PER_SEC >= 990 ) cout << ans << endl , exit(0);
    int val = hashh ( temp );
    if ( vis[val] ) return;
    vis[val] = 1;
    for ( int i = 2 ; i < n ; i ++ )
    {
        int tmp = temp[i];
        temp[i] = temp[i+1] + temp[i-1] - temp[i];
        ans = min ( check() , ans );
        dfs();
        temp[i] = tmp;
    }
}

signed main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    st = clock();
    n = read();
    for ( int i = 1 ; i <= n ; i ++ ) a[i] = temp[i] = read();
    dfs();
    cout << ans << endl;
    return 0;
}

/*

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

P7963 [NOIP2021] 棋局

就要 \(32pts\),但是写了 \(150+\) 行。

分成三种道路来 \(bfs\) 即可。

#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
int dx[4] = { 0 , 1 , 0 , -1 };
int dy[4] = { 1 , 0 , -1 , 0 };
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;

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 , qq , ans = inf , vis[N][4] , down[N] , rgt[N];

struct node { int col , lv; } mp[N];

int id ( int i , int j ) { return ( i - 1 ) * m + j; }

struct que { int x , y , dis , op , fx; }; // 1普通 2互通 3直行
queue<que> q;

int check ( int x , int y ) { return 1 <= x && x <= n && 1 <= y && y <= m; }

int bfs ( int sx , int sy )
{
    memset ( vis , 0 , sizeof vis );

    //普通。
    for ( int i = 0 ; i < 4 ; i ++ )//方向:下0平1
    {
        int tx = sx + dx[i] , ty = sy + dy[i];
        if ( !check ( tx , ty ) ) continue;
        int toop = ( dy[i] ? rgt[id(min(sx,tx),min(sy,ty))] : down[id(min(sx,tx),min(sy,ty))] );
        if ( toop != 1 ) continue;

        if ( mp[id(tx,ty)].lv )
        {
            if ( mp[id(sx,sy)].col != mp[id(tx,ty)].col && mp[id(sx,sy)].lv >= mp[id(tx,ty)].lv ) vis[id(tx,ty)][toop] = 1;
            continue;
        }
        vis[id(tx,ty)][toop] = 1;
    }

    //op2
    q.push ( { sx , sy , 0 , 0 , 0 } );
    while ( !q.empty() )
    {
        int x = q.front().x , y = q.front().y , dis = q.front().dis , op = q.front().op , fx = q.front().fx; q.pop();
        if ( dis == 0 ) 
        {
            for ( int i = 0 ; i < 4 ; i ++ )//方向:下0平1
            {
                int tx = x + dx[i] , ty = y + dy[i];
                int toop = ( dy[i] ? rgt[id(min(x,tx),min(y,ty))] : down[id(min(x,tx),min(y,ty))] );
                if ( !check ( tx , ty ) || vis[id(tx,ty)][2] || toop != 2 ) continue;
                if ( mp[id(tx,ty)].lv )
                {
                    if ( mp[id(sx,sy)].col != mp[id(tx,ty)].col && mp[id(sx,sy)].lv >= mp[id(tx,ty)].lv ) vis[id(tx,ty)][toop] = 1;
                    continue;
                }
                q.push ( { tx , ty , dis + 1 , toop , i } ) , vis[id(tx,ty)][toop] = 1;
            }
        }
        else 
        {
            int tx = x + dx[fx] , ty = y + dy[fx];
            int toop = ( dy[fx] ? rgt[id(min(x,tx),min(y,ty))] : down[id(min(x,tx),min(y,ty))] );
            if ( !check ( tx , ty ) || vis[id(tx,ty)][2] || toop != 2 ) continue;

            if ( mp[id(tx,ty)].lv )
            {
                if ( mp[id(sx,sy)].col != mp[id(tx,ty)].col && mp[id(sx,sy)].lv >= mp[id(tx,ty)].lv ) vis[id(tx,ty)][toop] = 1;
                continue;
            }
            q.push ( { tx , ty , dis + 1 , toop , fx } ) , vis[id(tx,ty)][toop] = 1;
        }
    }

    q.push ( { sx , sy , 0 , 0 , 0 } );
    while ( !q.empty() )
    {
        int x = q.front().x , y = q.front().y , dis = q.front().dis , op = q.front().op , fx = q.front().fx; q.pop();
        for ( int i = 0 ; i < 4 ; i ++ )//方向:下0平1
        {
            int tx = x + dx[i] , ty = y + dy[i];
            int toop = ( dy[i] ? rgt[id(min(x,tx),min(y,ty))] : down[id(min(x,tx),min(y,ty))] );
            if ( !check ( tx , ty ) || vis[id(tx,ty)][3] || toop != 3 ) continue;

            if ( mp[id(tx,ty)].lv )
            {
                if ( mp[id(sx,sy)].col != mp[id(tx,ty)].col && mp[id(sx,sy)].lv >= mp[id(tx,ty)].lv ) vis[id(tx,ty)][toop] = 1;
                continue;
            }
            q.push ( { tx , ty , dis + 1 , toop , 0 } ) , vis[id(tx,ty)][toop] = 1;
        }
    }
    int res = 0; 
    for ( int i = 1 ; i <= n ; i ++ )
        for ( int j = 1 ; j <= m ; j ++ )
        {
            int flag = 0;
            for ( int k = 1 ; k <= 3 ; k ++ ) if ( vis[id(i,j)][k] ) flag = 1;
            res += flag;
        }
    return res;
}

/*
1
3 3 1
13
22
23
010
233
0 1 2 3
*/

int bfs3 ( int sx , int sy )
{
    int res = 0; 
    for ( int i = 0 ; i < 4 ; i ++ )//方向:下0平1
    {
        int tx = sx + dx[i] , ty = sy + dy[i];
        if ( !check ( tx , ty ) ) continue;
        int toop = ( dy[i] ? rgt[id(min(sx,tx),min(sy,ty))] : down[id(min(sx,tx),min(sy,ty))] );
        if ( toop != 1 ) continue;

        if ( mp[id(tx,ty)].lv )
        {
            if ( mp[id(sx,sy)].col != mp[id(tx,ty)].col && mp[id(sx,sy)].lv >= mp[id(tx,ty)].lv ) ++ res;
            continue;
        }
        ++ res;
    }
    return res;
}

char ch;
signed main ()
{
    ios::sync_with_stdio(false);
    cin.tie(0) , cout.tie(0);
    int T = read();
    while ( T -- )
    {
        memset ( mp , 0 , sizeof mp );
        memset ( rgt , 0 , sizeof rgt );
        memset ( down , 0 , sizeof down );
        n = read() , m = read() , qq = read();
        for ( int i = 1 ; i <= n ; i ++ )
            for ( int j = 1 ; j < m ; j ++ ) 
                cin >> ch , rgt[id(i,j)] = ( ch - '0' );
        for ( int i = 1 ; i < n ; i ++ )
            for ( int j = 1 ; j <= m ; j ++ ) 
                cin >> ch , down[id(i,j)] = ( ch - '0' );
        for ( int i = 1 ; i <= qq ; i ++ )
        {
            int col = read() , lv = read() , x = read() , y = read();
            mp[id(x,y)] = { col , lv };
            if ( n * m <= 5000 ) cout << bfs(x,y) << endl;
            else cout << bfs3(x,y) << endl;
        }
    }
    return 0;
}
posted @ 2023-11-15 10:23  Echo_Long  阅读(9)  评论(0编辑  收藏  举报