春季测试补题
P9117 [春季测试 2023] 涂色游戏
显然 后面的操作会覆盖前面的操作 那么我们为每一行和每一列记录一个颜色和时间戳
最后输出的时候比较行列时间戳的最大值对应的颜色即可
#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 fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int N = 1e6 + 5;
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 , q , len[N] , timlen[N] , row[N] , timrow[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
memset ( len , 0 , sizeof len );
memset ( timlen , 0 , sizeof timlen );
memset ( row , 0 , sizeof row );
memset ( timrow , 0 , sizeof timrow );
n = read() , m = read() , q = read();
for ( int i = 1 ; i <= q ; i ++ )
{
int op = read() , x = read() , c = read();
if ( op == 0 ) timlen[x] = i , len[x] = c;
else timrow[x] = i , row[x] = c;
}
for ( int i = 1 ; i <= n ; i ++ , cout.put(endl) )
for ( int j = 1 ; j <= m ; j ++ )
cout << ( timlen[i] > timrow[j] ? len[i] : row[j] ) << ' ';
}
return 0;
}
P9118 [春季测试 2023] 幂次
数据分治:
- \(k=1\) 直接输出 \(n\) 即可
- \(k\ge 3\) 从 \(2\) 开始枚举底数 暴力枚举指数即可 所有合法底数上界为 \(\sqrt[3]n\) 足以通过 注意需要加上 \(1^1=1\) 的情况
- \(k=2\) 考虑优化 因为 \(\sqrt[2]n\) 是 \(1e9\) 级别的 那么我们可以在沿用 \(2\) 方法的基础上 忽略所有的完全平方数 让最后的答案加上 \(\sqrt n\) 即可(因为 \(n\) 以内的完全平方数个数即为 \(\sqrt n\))
注意开 \(\_\_int128\) 和 \(long\ double\)
#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 fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
#define int __int128
const int N = 1e6 + 5;
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;
}
void write ( int x )
{
if ( x < 0 ) x = -x , cout.put ( '-' );
if ( x > 9 ) write ( x / 10 );
cout.put ( x % 10 + '0' );
}
int n , k , ans;
map<int,int> mp;
int ksm ( int base , int k )
{
int res = 1;
for ( ; k ; base *= base , k >>= 1 )
if ( k & 1 ) res *= base;
return res;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , k = read();
if ( k == 1 ) return write(n) , cout.put(endl) , 0;
else if ( k >= 3 )
{
ans = 1;
for ( int i = 2 ; i <= n ; i ++ )
{
if ( ksm ( i , k ) > n ) break;
int cur = ksm ( i , k );
for ( int j = k ; ; j ++ )
{
if ( cur > n ) break;
if ( !mp.count ( cur ) ) ++ ans , mp[cur] = 1;
cur *= i;
}
}
write(ans);
}
else
{
for ( int i = 2 ; i <= n ; i ++ )
{
if ( ksm ( i , 3 ) > n ) break;
int cur = ksm ( i , 3 );
for ( int j = 3 ; ; j ++ )
{
if ( cur > n ) break;
if ( !mp.count ( cur ) && ! ( (int)sqrtl((long long)cur) * (int)sqrtl((long long)cur) == cur ) ) ++ ans , mp[cur] = 1;
cur *= i;
}
}
write(ans+(int)sqrtl((long long)n));
}
return 0;
}
P9119 [春季测试 2023] 圣诞树
乱搞 \(95pts\)
对于 \(n\le 9\) 的点 全排列即可通过 (\(30pts\))
对于 \(n\le 18\) 可以状压 (\(60pts\))
对于性质 \(B\) 直接顺序输出即可
对于其他点 充分发扬人类智慧 将所有的点按照 \(y\) 坐标进行排序输出即可
注意 \(long\ double\)
#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 fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int N = 1e6 + 5;
const double inf = 0x3f3f3f3f;
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 , k , temp[N] , t[N];
double res , minn = inf , maxxy;
struct node { double x , y; int id; } a[N];
double dis ( node a , node b ) { return sqrtl ( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) ); }
namespace sub1
{
void main()
{
for ( int i = 1 ; i <= n ; i ++ ) t[i] = i;
do
{
if ( t[1] != k ) continue;
double tt = 0;
for ( int i = 1 ; i < n ; i ++ ) tt += dis ( a[t[i]] , a[t[i+1]] );
if ( tt < minn ) memcpy ( temp , t , sizeof t ) , minn = tt;
} while ( next_permutation ( t + 1 , t + n + 1 ) );
for ( int i = 1 ; i <= n ; i ++ ) cout << temp[i] << ' ';
}
}
namespace sub2
{
int g[N][20];
double f[N][20];
vector<int> ans;
void main ()
{
for ( int s = 0 ; s < ( 1 << n ) ; s ++ )
for ( int j = 1 ; j <= n ; j ++ ) f[s][j] = inf;
f[1<<k-1][k] = 0;
for ( int s = 0 ; s < ( 1 << n ) ; s ++ )
for ( int i = 1 ; i <= n ; i ++ )//pre
if ( ( s & 1 << i - 1 ) && f[s][i] != inf )
for ( int j = 1 ; j <= n ; j ++ )//now
if ( f[s|1<<j-1][j] > f[s][i] + dis ( a[i] , a[j] ) && ! ( s & 1 << j - 1 ) )
f[s|1<<j-1][j] = f[s][i] + dis ( a[i] , a[j] ) , g[s|1<<j-1][j] = i;
int ed = 0 , s = (1<<n) - 1 , temp;
double minn = inf;
for ( int i = 1 ; i <= n ; i ++ ) if ( minn > f[s][i] ) minn = f[s][i] , ed = i;
while ( ed ) ans.eb(temp=ed) , ed = g[s][ed] , s ^= 1 << temp - 1;
reverse ( ans.begin() , ans.end() );
for ( auto v : ans ) cout << v << ' ';
}
}
namespace sub3
{
void solve ()
{
sort ( a + 1 , a + n + 1 , [](const node &a , const node &b ) { return a.y == b.y ? a.id < b.id : a.y > b.y; } );
for ( int i = 1 ; i <= n ; i ++ ) cout << a[i].id << ' ';
}
void solveB() { for ( int i = 1 ; i <= n ; i ++ ) cout << i << ' '; }
void main ()
{
int pdb = 1;
for ( int i = 1 ; i < n ; i ++ ) if ( a[i].x > a[i+1].x || a[i].y < a[i+1].y ) { pdb = 0; break; }
if ( pdb ) solveB();
else solve();
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ )
{
cin >> a[i].x >> a[i].y , a[i].id = i;
if ( a[i].y > maxxy ) k = i , maxxy = a[i].y;
}
if ( n <= 9 ) sub1::main();
else if ( n <= 18 ) sub2::main();
else sub3::main();
return 0;
}
P9120 [春季测试 2023] 密码锁
\(random\_shuffle\) 大法好
\(25pts\) 性质+暴搜显然
对于后面的点 我们考虑一个错误贪心:从 \(1\) 到 \(n\) 来贪心 枚举每一种挂锁状态对于答案的贡献 取最小贡献累加即可
但这种贪心是有后效性的 但是对于一些特定的顺序可以解出正确的解
那么我们 \(random\_shuffle\) \(200\) 次 就有很大概率解出正解()
赛时 \(25pts\) 代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define inl inline
const int N = 3e5 + 5;
const int inf = 4e18;
inl int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = x * 10 + ( ch - '0' ); ch = getchar(); }
return x * f;
}
int T , k , n , a[N] , mp[5][N] , temp[5][N] , ans = inf;
void dfs ( int stp )
{
if ( stp == n + 1 )
{
int maxx , minn , anstemp = -inf;
for ( int i = 1 ; i <= k ; i ++ )
{
maxx = -inf , minn = inf;
for ( int j = 1 ; j <= n ; j ++ )
maxx = max ( temp[i][j] , maxx ) , minn = min ( temp[i][j] , minn );
anstemp = max ( anstemp , maxx - minn );
}
ans = min ( anstemp , ans );
return;
}
for ( int tt = 1 ; tt <= k ; tt ++ )
{
for ( int i = 1 ; i <= k ; i ++ ) temp[i][stp] = mp[(i+tt)%k+1][stp];
dfs ( stp + 1 );
for ( int i = 1 ; i <= k ; i ++ ) temp[i][stp] = 0;
}
}
void solve ()
{
while ( T -- )
{
ans = inf;
n = read();
for ( int i = 1 ; i <= k ; i ++ )
for ( int j = 1 ; j <= n ; j ++ )
mp[i][j] = read();
dfs ( 1 );
printf ( "%lld\n" , ans );
}
}
signed main ()
{
T = read() , k = read();
if ( k == 1 )
{
while ( T -- )
{
n = read();
int maxx = -inf , minn = inf;
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read() , maxx = max ( a[i] , maxx ) , minn = min ( a[i] , minn );
printf ( "%lld\n" , maxx - minn );
}
}
else solve();
return 0;
}
\(100pts\): 纯随机化
#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 fi first
#define se second
#define print(x) cerr<<#x<<'='<<x<<endl
#define getchar() cin.get()
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f;
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 , k , a[N][10] , maxx[10] , minn[10];
signed main ()
{
// freopen ( "lock2.in" , "r" , stdin );
srand(random_device{}());
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read() , k = read();
while ( T -- )
{
n = read();
for ( int i = 1 ; i <= k ; i ++ ) for ( int j = 1 ; j <= n ; j ++ ) a[j][i] = read();
int cnt = 200 , ans = inf;
for ( int i = 1 ; i <= cnt ; i ++ )
{
random_shuffle ( a + 1 , a + n + 1 );
//这里的random只会改变行上下的位置
memset ( maxx , -inf , sizeof maxx );
memset ( minn , inf , sizeof minn );
for ( int j = 1 ; j <= n ; j ++ )
{
int tempval = inf , minstp = 0;
for ( int stp = 0 ; stp < k ; stp ++ )
{
int kk = 0;
for ( int x = 1 ; x <= k ; x ++ )
{
int tmp = ( x + stp - 1 ) % k + 1;
kk = max ( kk , max ( maxx[x] , a[j][tmp] ) - min ( minn[x] , a[j][tmp] ) );
}
if ( kk < tempval ) tempval = kk , minstp = stp;
}
for ( int x = 1 ; x <= k ; x ++ )
{
int tmp = ( x + minstp - 1 ) % k + 1;//最优情况下转多少圈
maxx[x] = max ( maxx[x] , a[j][tmp] );
minn[x] = min ( minn[x] , a[j][tmp] );
}
// cout << n << ' < endl;' << j << "check" << endl;
// for ( int l = 1 ; l <= k ; l ++ ) cout << maxx[l] << ' ' << minn[l] << endl;
// cout << "check1" <
if ( tempval >= ans ) break;
}
// for ( int i = 1 ; i <= k ; i ++ , cout.put(endl) ) for ( int j = 1 ; j <= n ; j ++ ) cout << a[j][i] << ' ';
int res = 0;
for ( int j = 1 ; j <= k ; j ++ ) res = max ( res , maxx[j] - minn[j] );
ans = min ( ans , res );
}
cout << ans << endl;
}
return 0;
}
/*
2 3
2
1 2
2 1
1 2
3
1 2 1
2 3 2
3 1 3
*/