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;
}