国庆集训做题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\)先手,每次操作可以进行以下操作 :

  1. 选定一个还有石子的石子堆,记剩下的石子为\(a_i\)​。

  2. 选定一个\(1\) \(≤\) \(x ≤ a_i\) ​,将该堆中的 \(x\)个石子移走。

  3. 选定一个\(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)\)

posted @ 2025-10-03 19:56  Nailong2357  阅读(40)  评论(6)    收藏  举报