国庆集训做题10.1 - 10.3
国庆集训做题
CSP-S模拟25
t1 : 爱丽丝的数位划分
题意简述 : 将序列A划分为k个不相交连续非空子序列,求最大的总优美度。
优美度指子序列中十进制表示数字不同的个数,一个方案的优美度是所有子序列优美度的和
首先很容易想到 \(n^2m\) 做法,也就是枚举上一个端点进行转移
然后注意到如果多个端点能产生相同的贡献,则端点最后的肯定更优,此时发现贡献的产生只有十种,提前预处理可以做到 \(O(n^2)\) ,多测记得清空
code:
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long
const int N = 2e3 + 20 ;
int n , T , a[N] , f[N][N] , pos[N][20] , m ,b[N] ;
signed main(){
freopen("partition.in","r",stdin);freopen("partition.out","w",stdout);
ios :: sync_with_stdio(false) , cin.tie(0) , cout.tie(0) ;
cin >> T ;
while(T--){
cin >> n >> m ;
string s ;
for(int i = 1 ; i <= n ;i++){
cin >> s ;
for(int j = 0 ; j < s.size() ; ++j){
b[i] |= (1 << (s[j] - '0' + 1));
}
}
for(int i = 1; i <= n ; i++){
int l = b[i] ;
for(int j = i ; j >= 1 ; j--){
l |= b[j];
int sum = __builtin_popcount(l);
pos[i][sum] = max(pos[i][sum] , j);
}
}
for(int i = 1 ; i <= n ; i++){
for(int k = 1 ; k <= m ; k++){
for(int j = 0 ; j <= 10 ; j++){
if(pos[i][j])f[i][k] = max(f[i][k] , f[pos[i][j] - 1][k - 1] + j) ;
}
}
}
cout << f[n][m] << endl ;
for(int i = 1 ; i <= n ; i++){
for(int j = 1 ; j <= m ; j++){
f[i][j] = 0 ;
b[i] = 0 ;
}
for(int j = 1 ; j <= 19 ; j++)pos[i][j] = 0 ;
}
}
return 0;
}
t2 : 爱丽丝的新运算
给出一个由无平方因子数组成的序列,求子序列能构成 : 质因子都出现过偶数次
线性基bitset维护每个序列中质数是否存在的01串,将大于 \(sqrt{n}\) 的数单独处理 , 剩下的插进线性基维护即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353 ;
const int N = 1e6 + 20;
const int M = 1e6 + 20 ;
int T , n , a[N];
int cnt , prime[N] ;
bool not_prime[N] ;
void xxs(){
for(int i = 2 ; i <= 1000010 ; i++){
if(!not_prime[i]){
prime[++cnt] = i ;
}
for(int j = 1 ; j <= cnt ; j++){
if(i * prime[j] > 1000010 )break ;
not_prime[i * prime[j]] = 1 ;
if(i % prime[j] == 0)break ;
}
}
}
int ans ;
bitset<180>b[N];
bitset<180>d[M];
void insert(bitset<180>B){
int flag = 0 ;
for(int i = 170 ; i >= 0 ; --i){
if(!(B[i]))continue ;
if(d[i].count())B ^= d[i];
else{
d[i] |= B ;
flag = 1 ;
break ;
}
}
if(flag == 0)ans++;
}
int qpow(int a , int b){
int res = 1 ;
while(b){
if(b & 1)res = res * a % mod ;
a = a * a % mod ;
b >>= 1 ;
}
return res ;
}
int vis[N] ;
vector<int>G[N];
signed main(){
freopen("calc.in","r",stdin);freopen("calc.out","w",stdout);
ios :: sync_with_stdio(false) , cin.tie(0) , cout.tie(0) ;
xxs() ;
cin >> T ;
for(int _ = 1 ; _ <= T ; _++){
cin >> n ;
for(int i = 1 ; i <= n ; ++i){
cin >> a[i] ;
}
ans = 0 ;
sort( a + 1 , a + 1 + n );
for(int i = 1 ; i <= n ; i++){
if(a[i] == 1){
++ans ;
continue ;
}
int k = a[i] ;
for(int j = 1 ; j <= cnt ; j++){
if(j == 170)break ;
if(k % prime[j] == 0){
k /= prime[j] ;
b[i][j] = 1 ;
}
if( k == 1)break ;
}
if(k == 1){
insert(b[i]);
}
else{
if(vis[k]){
bitset<180>B ;
B = b[i] ^ b[vis[k]];
insert(B);
}
else{
vis[k] = i ;
}
}
}
for(int i = 1 ; i <= n ; i++){
b[i].reset();
d[i].reset();
}
memset(vis , 0 ,sizeof(vis));
}
return 0;
}
t3 : 爱丽丝的幻方
给出n * n的一个矩阵,每个矩阵初始状态都是由左到右从上到下编号为1 - n
矩阵支持向右,向下平移操作,对角翻转,旋转,纵向翻转,横向翻转
给出操作后的矩阵,最少需要多少步
观察到1 , 2 , n + 1 三个点相对位置始终不变 , 使用bfs求值
代码太丑了...不贴了
CSP-S 模拟26
t1 : median
求 \(\sum\limits_{i = 1}^n\sum\limits_{j = 1}^n\sum\limits_{k = 1}^n\sum\limits_{l = 1}^n\sum\limits_{m = 1}^n med(A_i,B_j,C_k,D_l,E_m)\) \(mod\) \(998244353\)
其中\(med(a,b,c,d,e)\)为\(a,b,c,d,e\)的中位数。
开题的时候吓坏了
考虑\(A,B,C,D,E\)中哪个数会成为中位数,最后看统计答案发现会重复 , 所以采取将第二元设为字母的方法,他进行排序,就不用容斥了
一个好方法就是输入\(A\)时把数组内元素\(*5\) ,\(B_i * 5 + 1\)以此类推避免排序
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10 ;
const int mod = 998244353 ;
int n , a[N] , a1[N] , b[N] , b1[N] , c[N] , c1[N] , d[N] , d1[N] , e[N] , e1[N] , ans ;
signed main(){
freopen("median.in","r",stdin);freopen("median.out","w",stdout);
ios :: sync_with_stdio(false) , cin.tie(0) , cout.tie(0);
cin >> n ;
for(int i = 1 ; i <= n ; ++i)cin >> a[i] , a1[i] = (a[i] << 3) | 1 ;
sort(a + 1,a + 1 + n) , sort(a1 + 1,a1 + 1 + n);
for(int i = 1 ; i <= n ; ++i)cin >> b[i] ,b1[i] = (b[i] << 3) | 2 ;
sort(b + 1,b + 1 + n) , sort(b1 + 1,b1 + 1 + n);
for(int i = 1 ; i <= n ; ++i)cin >> c[i] , c1[i] = (c[i] << 3) | 3;
sort(c + 1,c + 1 + n) , sort(c1 + 1,c1 + 1 + n);
for(int i = 1 ; i <= n ; ++i)cin >> d[i] , d1[i] = (d[i] << 3) | 4 ;
sort(d + 1,d + 1 + n) , sort(d1 + 1,d1 + 1 + n);
for(int i = 1 ; i <= n ; ++i)cin >> e[i] , e1[i] = (e[i] << 3) | 5 ;
sort(e + 1,e + 1 + n) , sort(e1 + 1,e1 + 1 + n);
for(int i = 1 ; i <= 5 ; i++){
for(int j = 1 ; j <= n ; j++){
if(i == 1){
int bx = lower_bound(b1 + 1, b1 + 1 + n , a1[j]) - b1 - 1 , by = n - bx ;
int cx = lower_bound(c1 + 1, c1 + 1 + n , a1[j]) - c1 - 1 , cy = n - cx ;
int dx = lower_bound(d1 + 1, d1 + 1 + n , a1[j]) - d1 - 1 , dy = n - dx ;
int ex = lower_bound(e1 + 1, e1 + 1 + n , a1[j]) - e1 - 1 , ey = n - ex ;
// cout << bx << " " <<cx << " " << dx << " " << ex <<endl ;
ans += (bx % mod * cx % mod * dy % mod * ey % mod * a[j] % mod) % mod +
(bx % mod * dx % mod * cy % mod * ey % mod * a[j] % mod) % mod +
(bx % mod * ex % mod * cy % mod * dy % mod * a[j] % mod) % mod +
(cx % mod * ex % mod * by % mod * dy % mod * a[j] % mod) % mod +
(cx % mod * dx % mod * by % mod * ey % mod * a[j] % mod) % mod +
(dx % mod * ex % mod * by % mod * cy % mod * a[j] % mod) % mod ;
ans %= mod ;
}
if(i == 2){
int ax = lower_bound(a1 + 1, a1 + 1 + n , b1[j]) - a1 - 1, ay = n - ax ;
int cx = lower_bound(c1 + 1, c1 + 1 + n , b1[j]) - c1 - 1, cy = n - cx ;
int dx = lower_bound(d1 + 1, d1 + 1 + n , b1[j]) - d1 - 1, dy = n - dx ;
int ex = lower_bound(e1 + 1, e1 + 1 + n , b1[j]) - e1 - 1, ey = n - ex ;
// cout << ax << " " << cx << " " << dx << " " << ex << endl ;
ans += (ax % mod * cx % mod * dy % mod * ey % mod * b[j] % mod) % mod +
(ax % mod * dx % mod * cy % mod * ey % mod * b[j] % mod) % mod +
(ax % mod * ex % mod * cy % mod * dy % mod * b[j] % mod) % mod +
(cx % mod * ex % mod * ay % mod * dy % mod * b[j] % mod) % mod +
(cx % mod * dx % mod * ay % mod * ey % mod * b[j] % mod) % mod +
(dx % mod * ex % mod * ay % mod * cy % mod * b[j] % mod) % mod ;
ans %= mod ;
}
if(i == 3){
int ax = lower_bound(a1 + 1, a1 + 1 + n , c1[j]) - a1 - 1 , ay = n - ax ;
int bx = lower_bound(b1 + 1, b1 + 1 + n , c1[j]) - b1 - 1, by = n - bx ;
int dx = lower_bound(d1 + 1, d1 + 1 + n , c1[j]) - d1 - 1, dy = n - dx ;
int ex = lower_bound(e1 + 1, e1 + 1 + n , c1[j]) - e1 - 1, ey = n - ex ;
// cout << ax << " " << bx << " " << dx << " " <<ex << endl ;
ans += (ax % mod * bx % mod * dy % mod * ey % mod * c[j] % mod) % mod +
(ax % mod * dx % mod * by % mod * ey % mod * c[j] % mod) % mod +
(ax % mod * ex % mod * by % mod * dy % mod * c[j] % mod) % mod +
(bx % mod * ex % mod * ay % mod * dy % mod * c[j] % mod) % mod +
(bx % mod * dx % mod * ay % mod * ey % mod * c[j] % mod) % mod +
(dx % mod * ex % mod * ay % mod * by % mod * c[j] % mod) % mod ;
ans %= mod ;
}
if(i == 4){
int ax = lower_bound(a1 + 1, a1 + 1 + n , d1[j]) - a1 - 1, ay = n - ax ;
int bx = lower_bound(b1 + 1, b1 + 1 + n , d1[j]) - b1 - 1, by = n - bx ;
int cx = lower_bound(c1 + 1, c1 + 1 + n , d1[j]) - c1 - 1, cy = n - cx ;
int ex = lower_bound(e1 + 1, e1 + 1 + n , d1[j]) - e1 - 1, ey = n - ex ;
// cout <<ax << " " << bx << " " << cx << " " << ex << endl ;
ans += (ax % mod * bx % mod * cy % mod * ey % mod * d[j] % mod) % mod +
(ax % mod * cx % mod * by % mod * ey % mod * d[j] % mod) % mod +
(ax % mod * ex % mod * by % mod * cy % mod * d[j] % mod) % mod +
(bx % mod * ex % mod * ay % mod * cy % mod * d[j] % mod) % mod +
(bx % mod * cx % mod * ay % mod * ey % mod * d[j] % mod) % mod +
(cx % mod * ex % mod * ay % mod * by % mod * d[j] % mod) % mod ;
ans %= mod ;
}
if(i == 5){
int ax = lower_bound(a1 + 1, a1 + 1 + n , e1[j]) - a1 - 1 , ay = n - ax ;
int bx = lower_bound(b1 + 1, b1 + 1 + n , e1[j]) - b1 - 1 , by = n - bx ;
int cx = lower_bound(c1 + 1, c1 + 1 + n , e1[j]) - c1 - 1 , cy = n - cx ;
int dx = lower_bound(d1 + 1, d1 + 1 + n , e1[j]) - d1 - 1 , dy = n - dx ;
// cout << ax << " " << bx << " " << cx << " " << dx << endl;
ans += (ax % mod * bx % mod * cy % mod * dy % mod * e[j] % mod) % mod +
(ax % mod * cx % mod * by % mod * dy % mod * e[j] % mod) % mod +
(ax % mod * dx % mod * by % mod * cy % mod * e[j] % mod) % mod +
(bx % mod * dx % mod * ay % mod * cy % mod * e[j] % mod) % mod +
(bx % mod * cx % mod * ay % mod * dy % mod * e[j] % mod) % mod +
(cx % mod * dx % mod * ay % mod * by % mod * e[j] % mod) % mod ;
ans %= mod ;
}
}
}
cout << ans << endl ;
return 0;
}
t2 : travel
ccb
t3 : game
有\(n\)堆石子,第\(i\)堆石子有\(a_i\)个,\(A\)和\(B\)玩游戏,\(A\)先手,每次操作可以进行以下操作 :
-
选定一个还有石子的石子堆,记剩下的石子为\(a_i\)。
-
选定一个\(1\) \(≤\) \(x ≤ a_i\) ,将该堆中的 \(x\)个石子移走。
-
选定一个\(0\) \(≤\) \(y\) \(≤\) \(ai\) \(−x\),将该堆中的\(y\)个石子以任意方式分配到剩余的非空石子堆中。
第一个不能操作者输,问\(A\)是否有必胜策略
注意到当能两两分组时,就是必败局面
同时,必胜局面可以转化到必败局面 : 把最大的拿出来给小的补上让他能两两分组,此时必败
所以只需要判断他是否能两两分组
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 20 ;
int T , n , a[N] ;
int main(){
freopen("game.in","r",stdin);freopen("game.out","w",stdout);
ios :: sync_with_stdio(false) , cin.tie(0) , cout.tie(0) ;
cin >> T ;
while(T--){
cin >> n ;
for(int i = 1 ; i <= n ;++i)cin >> a[i] ;
sort(a + 1, a + 1 + n);
int f = 0 ;
for(int i = n ; i >= 1 ; i--){
if(a[i] != a[i - 1]){
if((n - i + 1) & 1){
f = 1 ;
}
}
}
if(!f)cout << "No" << endl;
else cout << "Yes" << endl ;
}
return 0;
}
2025多校CSP模拟赛1
t1 : Acowdemia
- 水题
- 直接判断是否有
GC
CG
即可
// ubsan: undefined
// accoders
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 20;
int mp[N][N], bj[N][N], cnt1[N][N];
int dx[4] = { 1, 0, -1, 0 };
int dy[4] = { 0, 1, 0, -1 };
int n, m, ans;
int main() {
ios ::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
string s;
for (int i = 1; i <= n; ++i) {
cin >> s;
for (int j = 0; j < m; ++j) {
if (s[j] == 'C')mp[i][j + 1] = 1;
if (s[j] == 'G')mp[i][j + 1] = 2;
if (s[j] == 'G')++ans;
if (s[j] == '.')mp[i][j + 1] = 3;
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (mp[i][j] == 2) {
int cnt = 0;
for (int d = 0; d < 4; ++d) {
int x = i + dx[d], y = j + dy[d];
if (x < 1 or x > n or j < 1 or j > m)
continue;
if (mp[x][y] == 1)++cnt;
}
cnt1[i][j] = cnt;
int f = 0;
if (cnt < 2) {
ans--;
continue;
} else {
if (bj[i][j])continue;
else {
if (cnt == 2) {
if (i > 1 and i <= n and j >= 1 and j < m) {
if (mp[i - 1][j] == 1 and mp[i][j + 1] == 1 and mp[i - 1][j + 1] == 2 and
cnt1[i - 1][j + 1] == 2) {
f = 1;
bj[i - 1][j + 1] = 1;
}
}
if (i > 1 and i <= n and j > 1 and j <= m) {
if (mp[i - 1][j] == 1 and mp[i][j - 1] == 1 and mp[i - 1][j - 1] == 2 and
cnt1[i - 1][j - 1] == 2) {
f = 1;
bj[i - 1][j + 1] = 1;
}
}
if (i >= 1 and i < n and j > 1 and j <= m) {
if (mp[i][j - 1] == 1 and mp[i + 1][j] == 1 and mp[i + 1][j - 1] == 2 and
cnt1[i + 1][j - 1] == 2) {
f = 1;
bj[i - 1][j + 1] = 1;
}
}
if (i >= 1 and i < n and j >= 1 and j < m) {
if (mp[i + 1][j] == 1 and mp[i][j + 1] == 1 and mp[i + 1][j + 1] == 2 and
cnt1[i + 1][j + 1] == 2) {
f = 1;
bj[i + 1][j + 1] = 1;
}
}
} else {
continue;
}
}
}
if (f == 1)ans--;
}
}
}
cout << ans << endl;
return 0;
}
t2 : Transmutation
越做越像网络流,可惜不是
每次二分能制多少Pb
对于不够的情况,递归下去看看后面的能不能填上,如果能,就可以,否则就不行
对于有环的情况 :如果一个点被经过n次那么就一定不行(注意这是假做法,能过赛时测试数据,但是过不了@wang54321的hack)
但是可以换成递推形式,@QEDQEDQED 递推形式通过了hack数据
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1010 ;
int a[N] , c[N] , n , vis[N];
struct Pb{
int x , y;
}b[N];
bool dfs(int k,int tp){
if(a[tp] >= k ){
a[tp] -= k;
return 1;
}
if(++vis[tp] > n)return 0;
k -= a[tp];
a[tp] = 0;
bool flag = dfs(k , b[tp].x);
if(flag == 0)return 0;
flag = dfs(k , b[tp].y);
if(!flag)return 0;
else return 1;
}
bool check(int k){
for(int i = 1 ; i <= n ;i++)
c[i] = a[i] , vis[i]=0 ;
bool ans = dfs(k , 1);
for(int i = 1 ; i <= n ;i++)a[i] = c[i] ;
return ans;
}
int T , to;
signed main(){
cin >> T ;
while(T--){
cin >> n ;
for(int i = 1 ;i <= n;i++){
cin >> b[i].x >> b[i].y ;
}
int sum = 0;
for(int i = 1;i <= n;i++){
cin >> a[i] , sum += a[i];
}
int l = a[1] , r = sum + 91 ;
int ans = 0;
while(l <= r){
int mid = (l + r) / 2;
if(check(mid)){
ans = mid;
l = mid + 1;
}else{
r = mid - 1;
}
}
printf("Case #%lld: %lld\n",++to,ans);
for(int i = 1 ; i <= n ; i++){
b[i].x = b[i].y = a[i] = 0;
}
}
return 0;
}
t3 : Magneti
这里用了一个trick:预设型DP
首先把磁铁紧贴一起,剩下的插板法处理
按照升序排序,之后就不用处理贡献了
设 \(f_{i,j,k}\) 表示前i个磁铁分j个连通块,用了k个空位的方案数
转移有:
插后面 \(f_{i,j,k}\) \(=\) \(f_{i−1,j−1,k−1}\)
插之前连通块的两端, \(f_{i,j,k}\) \(=\) \(2\) \(×\) \(f_{i−1,j,k}\) \(−len(i)×j\)
并两个连通块 \(f_{i,j,k}\) \(=\) \(f_{i−1,j+1,k}\) \(−2len(i)+1×(j+1)×j\)
答案是 \(\sum\ i≥1\) \(f_{n,1,i}\) \(×(m−i+n)\)

浙公网安备 33010602011771号