Loading

「解题报告」2023-10-31 模拟赛

A

(a.pas/c/cpp)

【题目描述】

对于给定的一个正整数 \(n\),判断 \(n\) 是否能分成若干个正整数之和(可以重复),其中每个正整数都能表示成两个质数乘积。

【输入描述】

第一行一个正整数 \(q\),表示询问组数。

接下来 \(q\) 行,每行一个正整数 \(n\),表示询问。

【输出描述】

\(q\) 行,每行一个正整数,为 \(0\)\(1\)\(0\) 表示不能,\(1\) 表示能。

【输入样例】

5 
1 
4 
5 
21 
25 

【输出样例】

0 
1 
0 
1 
1 

【样例解释】

\[4 = 2 \times 2 \\ 21= 6 + 15 = 2 \times 3 + 3 \times 5 \\ 25 = 6 + 9 + 10 = 2 \times 3 + 3 \times 3 + 2 \times 5\\ 25 = 4 + 4 + 4 + 4 + 9 = 2 \times 2 + 2 \times 2 + 2 \times 2 + 2 \times 2 + 3 \times 3 \]

【数据范围】

\(30\%\) 的数据满足:\(q \le 20,n \le 20\)

\(60\%\) 的数据满足:\(q \le 10000,n \le 5000\)

\(100\%\) 的数据满足:\(q \le 10^5,n \le 10^18\)

最小的偶和数是 \(4\),最小的奇和数是 \(9\),所以,\(n \ge 13\) 是一定有解。

\(n < 13\) 时,当 \(n = 1\)\(n\) 为质数时,\(n\) 不能被分解。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define orz puts("sym, cjx, gjh AK IOI!");

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? -x : x;
}

int q;
ll n;

bool check(ll n) {
	if (n == 1 || n == 2 || n == 3 || n == 5 || n == 7 || n == 11) {
		return 1;
	}
	return 0;
}

int main() {
	freopen("a.in", "r", stdin);
	freopen("a.out", "w", stdout);
	q = read<int>();
	while (q --) {
		n = read<ll>();
		if (check(n)) {
			puts("0");
		} else {
			puts("1");
		}
	}
	return 0;
}

B

(b.pas/c/cpp)

【题目描述】

有一个长度为 \(n\) 的自然数序列 \(a\),要求将这个序列恰好分成至少 \(m\) 个连续子段。每个子段的价值为该子段的所有数的按位异或。要使所有子段的价值按位与
的结果最大,输出这个最大值。

【输入描述】

第一行一个正整数 \(q\),表示询问组数。

接下来 \(q\) 组输入,每组输入两行:

第一行两个正整数 \(n,m\)

第二行 \(n\) 个正整数,描述序列 \(a\)

【输出描述】

一行一个正整数,表示答案。

【输入样例】

1 
5 3 
1 2 3 4 5 

【输出样例】

1 

【数据范围】

\(20\%\) 的数据:\(n \le 20\)

\(40\%\) 的数据:\(n \le 100, a_i < 256\)

\(60\%\) 的数据:\(n \le 100\)

\(100\%\) 的数据:\(1 \le q \le 12, 1 \le m \le n \le 1000,0 \le a_i < 2^30\)

贪心的想,二进制下,高位为 \(1\),那么这个数肯定大,且 \((1000)_2 > (0100)_2\) 的,所以我们贪心地让高位在经过运算后为 \(1\),,然后从高到低依次枚举每个数位,判断该数位为 \(1\) 时能否分成 \(\ge m\) 的连续子段。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define orz puts("sym, cjx, gjh AK IOI!");

template<typename T>
inline T read() {
	T x = 0;
	bool fg = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') {
		fg |= (ch == '-');
		ch = getchar();
	}
	while (ch >= '0' && ch <= '9') {
		x = (x << 3) + (x << 1) + (ch ^ 48);
		ch = getchar();
	}
	return fg ? -x : x;
}

const int N = 1010;

int n, m;
int siz[N][31], pd[32];
ll a[N];

void solve() {
	n = read<int>(), m = read<int>();
	for (int i = 1; i <= n; ++ i) {
		a[i] = read<ll>();
	}
	memset(pd, 0, sizeof pd);
	memset(siz, 0, sizeof siz);
	for (int i = 1; i <= n; ++ i) {
		int js = 0;
		ll tmp = a[i];
		while (tmp) {
			siz[i][js] += (tmp & 1);
			++ js;
			tmp >>= 1;
		}
		for (int j = 0; j <= 30; ++ j) {
			siz[i][j] += siz[i - 1][j];
		}
	}
	int maxx = -1;
	for (int i = 30; i >= 0; -- i) {
		if (siz[n][i] >= m) {
			maxx = i;
			break ;
		}
	}
	if (maxx == -1) {
		puts("0");
		return ;
	}
	ll ans = 0;
	pd[maxx] = 1;
	for (int i = maxx; i >= 0; -- i) {
		if ((siz[n][i] & 1) != (siz[n][maxx] & 1))	continue ;
		int sum = 0, las = 0, cnt = 0;
		for (int j = 1; j <= n; ++ j) {
			if (siz[j][i] - siz[j - 1][i]) {
				++ sum;
			}
			if (sum & 1) {
				bool fg = 1;
				for (int k = i + 1; k <= maxx; ++ k) {
					if (!pd[k])	continue ;
					if (((siz[j][k] - siz[las][k]) & 1) == 0) {
						fg = 0;
						break ;
					}
				}
				if (fg) {
					sum = 0;
					las = j;
					++ cnt;
				}
			}
		}
		if (cnt >= m) {
			pd[i] = 1;
			ans |= (1ll << i);
		}
	}
	printf("%lld\n", ans);
}

int main() {
	int T = read<int>();
	while (T --) {
		solve();
	}
	return 0;
}

C

(c.pas/c/cpp)

【题目描述】

定义一个排列 \(a\) 的价值为满足 \(|a[i]-i| \le 1\)\(i\) 的数量。

给出三个正整数 \(n,m,p\),求出长度为 \(n\) 且价值恰好为 \(m\) 的排列的个数对 \(p\) 取模的结果。

【输入描述】

第一行两个正整数 \(T,p\)\(T\) 为数据组数,\(p\) 为模数。

接下来 \(T\) 行,每行两个正整数 \(n,m\)

【输出描述】

\(T\) 行,每行一个非负数,表示答案。

【输入样例】

5 1887415157 
3 1 
3 2 
3 3 
50 10 
1500 200 

【输出样例】

1 
2 
3 
621655247 
825984474 

【数据范围】

\(10\%\) 的数据:\(n \le 10\)

\(30\%\) 的数据:\(n \le 15\)

\(50\%\) 的数据:\(n \le 200\)

另有 \(10\%\) 的数据:\(m=1\)

另有 \(10\%\) 的数据:\(m=n-1\)

\(100\%\) 的数据:\(1 \le T,n,m \le 2000,2 \le p \le 10^{12}\)

因为 \(n,m <= 2000\),而且 \(p\) 是事先给出的,所以我们可以一次性预处理出 \(n,m \le 2000\) 的答案。

考虑一个长度为 \(i\) 的排列如何变成长度为 \(i+1\) 的排列。

一种情况是我在它末尾加入了一个数 \(i+1\),另一种情况是我用 \(i+1\) 替换掉了原来排列中的一个数,然后把被换掉的数放到排列的末尾。

那么,这个排列权值的变化就是:

第一种情况:在它末尾加入了一个数 \(i+1\),权值 \(+1\)

第二种情况:用 \(i+1\) 替换掉一个数,权值 \(+=\) 加的贡献 \(-\) 换掉的数的贡献。

在 DP 当中,我们只需要考虑替换掉的数是否是 \(i\),以及 \(i\) 是否在位置 \(\dfrac{i}{i-1}\) 即可。总共有 \(5\) 种本质不同的状态,分类讨论转移即可。

复杂度 \(O(nm)\)

#include<bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N=2005;

int q,n,m,u,v;
LL p,ans,f[N][N][5],x;

int rd(){
	int re=0,f=1;char c=getchar();
	while ((c<'0')||(c>'9')) {if (c=='-') f=-f;c=getchar();}
	while ((c>='0')&&(c<='9')) {re=re*10+c-'0';c=getchar();}
	return re*f;
}

int main(){
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	cin>>q>>p;
	memset(f,0,sizeof(f));
	f[1][1][0]=1ll;
	f[2][2][0]=1ll;f[2][2][1]=1ll;
	
	n=2000;
	for (int i=2;i<n;++i)
		for (int j=0;j<=n;++j){
			for (int k=0;k<=4;++k){
				x=f[i+1][j+1][0]+f[i][j][k];
				x=(x<p)?x:(x-p);
				f[i+1][j+1][0]=x;
				u=j+((k%2)==0);
				v=1+(k!=0);
				x=f[i+1][u][v]+f[i][j][k];
				x=(x<p)?x:(x-p);
				f[i+1][u][v]=x;
			}
			
			if (f[i][j][0]>0ll){
				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][0]*(LL)(j-1))%p;
				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][0]*(LL)(i-j))%p;
			}
			if (f[i][j][1]>0ll){
				x=f[i+1][j][3]+f[i][j][1];
				x=(x<p)?x:(x-p);
				f[i+1][j][3]=x;
				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][1]*(LL)(j-2))%p;
				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][1]*(LL)(i-j))%p;
			}
			if (f[i][j][2]>0ll){
				x=f[i+1][j][3]+f[i][j][2];
				x=(x<p)?x:(x-p);
				f[i+1][j][3]=x;
				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][2]*(LL)(j-1))%p;
				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][2]*(LL)(i-j-1))%p;				
			}
			if (f[i][j][3]>0ll){
				x=f[i+1][j+1][3]+f[i][j][3];
				x=(x<p)?x:(x-p);
				f[i+1][j+1][3]=x;
				f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][3]*(LL)(j-1))%p;
				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][3]*(LL)(i-j-1))%p;	
			}
			if (f[i][j][4]>0ll){
				x=f[i+1][j+1][3]+f[i][j][4];
				x=(x<p)?x:(x-p);
				f[i+1][j+1][3]=x;		
				if (j>0) f[i+1][j-1][4]=(f[i+1][j-1][4]+f[i][j][4]*(LL)(j))%p;
				f[i+1][j][4]=(f[i+1][j][4]+f[i][j][4]*(LL)(i-j-2))%p;	
			}
		}
	
	for (;q>0;--q){
		cin>>n>>m;
		ans=(f[n][m][0]+f[n][m][1]+f[n][m][2]+f[n][m][3]+f[n][m][4])%p;
		cout<<ans<<'\n';
	}
	return 0;
}
posted @ 2023-10-31 17:34  yi_fan0305  阅读(20)  评论(0编辑  收藏  举报