2022年多校冲刺NOIP联训测试11

A.因子

用欧拉筛找出\(\sqrt n\)内的素数,然后跑埃筛

码风逐渐诡异

code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<cmath>

using namespace std;

typedef long long ll;
const int maxn = 2000005;
int prime[maxn], cnt, mi[maxn];
bool flag[maxn];

int main(){
	ll l, r; scanf("%lld%lld",&l,&r);
	int mx = sqrt(r);
	for(int i = 2; i <= mx; ++i){
		if(!flag[i])prime[++cnt] = i;
		for(int j = 1; j <= cnt && i * prime[j] <= mx; ++j){
			flag[i * prime[j]] = 1;
			if(i % prime[j] == 0)break;
		}
	}
	for(int j = 1; j <= cnt; ++j){
		for(ll k = ((l / prime[j]) + (l % prime[j] ? 1 : 0)) * prime[j]; k <= r; k += prime[j]){
			if(!mi[k - l + 1])mi[k - l + 1] = prime[j]; 
		}
	}
	for(ll i = l; i <= r; ++i)if(mi[i - l + 1])printf("%d\n",mi[i - l + 1]); else printf("%lld\n",i);
	return 0;
}

B. 数独

依题意模拟即可

code
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 21;
int mp[105][maxn][maxn];
char c[maxn];
void print(int id){
	for(int i = 1; i <= 9; ++i){
		printf("+-+-+-+-+-+-+-+-+-+\n");
		for(int j = 1; j <= 9; ++j)
		  printf("|%d",mp[id][i][j]);
		printf("|\n");
	}
	printf("+-+-+-+-+-+-+-+-+-+\n");
}
void copy(int id){
	for(int i = 1; i <= 9; ++i)
	  for(int j = 1; j <= 9; ++j)
	    mp[id][i][j] = mp[id - 1][i][j];
}
void delet(int id){
	int x, y; scanf("%d%d",&x,&y);
	if(mp[id][x][y]){
		mp[id][x][y] = 0;
		printf("OK!\n");
	}else printf("Error!\n");
}
void insert(int id){
	int x, y, k; scanf("%d%d%d",&x,&y,&k);
	if(mp[id][x][y]){
		printf("Error!\n");
		return;
	}
	for(int i = 1; i <= 9; ++i)if(mp[id][x][i] == k){printf("Error:row!\n");return;}
	for(int i = 1; i <= 9; ++i)if(mp[id][i][y] == k){printf("Error:column!\n");return;}
	int lx = ((x + 2) / 3) * 3, ly = ((y + 2) / 3) * 3;
	for(int i = 0; i <= 2; ++i)
	  for(int j = 0; j <= 2; ++j)
		if(mp[id][lx - i][ly - j] == k){printf("Error:square!\n");return;}	
	mp[id][x][y] = k;
	printf("OK!\n");
}
bool vis[maxn];
void query(int id){
	int x, y; scanf("%d%d",&x,&y);
	if(mp[id][x][y]){
		printf("Error!\n");
		return;
	}
	for(int i = 1; i <= 9; ++i)vis[i] = 0;
	for(int i = 1; i <= 9; ++i)vis[mp[id][x][i]] = 1;
	for(int i = 1; i <= 9; ++i)vis[mp[id][i][y]] = 1;
	int lx = ((x + 2) / 3) * 3, ly = ((y + 2) / 3) * 3;
	for(int i = 0; i <= 2; ++i)
	  for(int j = 0; j <= 2; ++j)
		vis[mp[id][lx - i][ly - j]] = 1;	
	int cnt = 0;
	for(int i = 1; i <= 9; ++i)if(!vis[i])++cnt;
	printf("%d\n",cnt);
	for(int i = 1; i <= 9; ++i)if(!vis[i])printf("%d\n",i);
}
bool vh[maxn][maxn], vl[maxn][maxn], vs[maxn][maxn];
int ID(int x, int y){
	return ((x - 1) / 3) * 3 + ((y + 2) / 3);
}
void merg(int id){
	int m1, m2; scanf("%d%d",&m1,&m2);
	int c1 = 0, c2 = 0;
	for(int i = 1; i <= 9; ++i)
	  for(int j = 1; j <= 9; ++j)
	    vh[i][j] = 0;
	for(int i = 1; i <= 9; ++i)
	  for(int j = 1; j <= 9; ++j)
	    vl[i][j] = 0;
	for(int i = 1; i <= 9; ++i)
	  for(int j = 1; j <= 9; ++j)
	    vs[i][j] = 0;
	for(int i = 1; i <= 9; ++i){
		for(int j = 1; j <= 9; ++j){
			if(mp[m1][i][j] && !vh[i][mp[m1][i][j]] && !vl[j][mp[m1][i][j]] && !vs[ID(i ,j)][mp[m1][i][j]]){
				mp[id][i][j] = mp[m1][i][j]; 
				vh[i][mp[m1][i][j]] = 1;
				vl[j][mp[m1][i][j]] = 1;
				vs[ID(i ,j)][mp[m1][i][j]] = 1;
				++c1; continue;
			}
			if(mp[m2][i][j] && !vh[i][mp[m2][i][j]] && !vl[j][mp[m2][i][j]] && !vs[ID(i ,j)][mp[m2][i][j]]){
				mp[id][i][j] = mp[m2][i][j]; 
				vh[i][mp[m2][i][j]] = 1;
				vl[j][mp[m2][i][j]] = 1;
				vs[ID(i ,j)][mp[m2][i][j]] = 1;
				++c2; continue;
			}
		}
	}
	printf("%d %d\n",c1,c2);
}
int main(){
	for(int i = 1; i <= 19; ++i){
		scanf("%s",c + 1);
		if(i & 1)continue;
		for(int j = 2; j <= 19; j += 2)mp[0][i >> 1][j >> 1] = c[j] - '0';
	}
	int T; scanf("%d", &T);
	for(int i = 1; i <= T; ++i){
		scanf("%s",c);
		switch(c[0]){
			case 'M': merg(i);break;
			case 'I': copy(i);insert(i);break;
			case 'D': copy(i);delet(i);break;
			case 'Q': copy(i);query(i);break;
			case 'P': copy(i);print(i);break;
		}
	}
	return 0;
}

C.分糖果

具体证明可以参考2014 年北京市高考理科数学第20 题

离离原上谱

按照\(min(a_i, b_j) < min(a_j, b_i)\)排序即可

考虑序列\((a_1,b_1), (a_2,b_2),(a_3, b_3)....\)

\(T_2 = max(a_1 + a_2, a_1 + b_1) + b_2\)

\(T_2 = max(a_2, b_1) +a_1 + b_2\)

只有\(min(a_2,b_1)\)没有贡献,我们令其最大显然需要\(min(a_1, b_2) < min(a_2, b_1)\)

如何扩展

继续推

\(T_3 = max(a_1 + a_2 + a_3, a_1 + b_1 + b_2, a_1 + a_ 2 + b_2) + b_3\)

......

画出图可以发现答案为从\(a_1\)\(b_n\)只向右向下走的所有路径的最大值

然后可以对其使用冒泡排序???不理解,具体看

2014年高考北京卷理科第20题详解与背景分析

发现"乱"中之"序" 体现数学之美——评析2014年高考北京卷理科20题

以及\(lyin\)大佬的分讨

证明传递性
已知$ \min( Ax, By ) < \min( Ay, Bx ) 且 \min( Bx, Cy ) < \min( By, Cx ) $
证明$ \min( Ax, Cy ) < \min( Ay, Cx ) $

若$ Bx \leq By $
可知$ Ax < Bx,Ax < Ay $

若$ Bx \leq Cx $ 则$ Ax < Ay,Ax < Cx $ 得证
若$ Bx > Cx $ 则$ Ax < Ay,Cy < Cx $ 得证

若$ Bx > By $
可知$ Cy < By,Cy < Cx $

若$ By \leq Ay $ 则$ Cy < Cx,Cy < Ay $ 得证
若$ By > Ay $ 则$ Cy < Cx,Ax < Ay $ 得证

他让我直接粘的

code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read(){
	int x = 0; char c = getchar();
	while(c < '0' || c > '9')c = getchar();
	do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c <= '9' && c >= '0');
	return x;
}
typedef long long ll;
const int maxn = 50005;
int p[maxn],a[maxn],b[maxn], n;
bool cmp(int x, int y){return min(a[x], b[y]) < min(a[y], b[x]);}
int main(){
	int T = read();
	for(int ask = 1; ask <= T; ++ask){
		n = read();
		for(int i = 1; i <= n; ++i)a[i] = read(), b[i] = read();
		ll ans = 0x3f3f3f3f3f3f3f3f;
		for(int i = 1; i <= n; ++i)p[i] = i;
		sort(p + 1, p + n + 1, cmp);
		ll c = 0,s = 0;
		for(int i = 1; i <= n; ++i){
			s += a[p[i]];
			c = max(c, s) + b[p[i]];
		}
		if(c <= ans){
			ans = c;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

D. 异或

如果不能正常工作,那么每一位的贡献显然可以分开考虑

我们处理\(p_i\)表示第\(i\)位为\(1\)的概率

那么$\large p_i = \lfloor\frac{n}{2^{i + 1}}\rfloor + max(0, n \mod 2^{i + 1} - 2^i) $

$\large ans = \sum2p_i (1 - p_i)2^i $

如果能正常工作,我们同样分开考虑

我们令\(B\),卡着上界走

如果上界该位为\(1\),那么对应的另一个数\(A\)无论该位为\(1/0\)都能填出有贡献的方案,而且一定合法

所以$ans += n2^i$

如果上界该位为\(0\),那么对应另一个数无论是\(1/0\)都不得不与之组合,那么有贡献的数就是

$n - $无贡献的数

考虑前面为\(0\)的数位的数量为\(cnt_0\)那么无论那些位置填\(1/0\)都是卡着上界的,有\(2^{cnt0}\)种,该位为\(0\)没有贡献,只有一种方案,对于后面的因为\(A\)没有卡界,所以可以随便选\(2^i\)

code
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
typedef long double ld;
using namespace std;
#define int long long
void print(ld a){
	int m = 0;
	while(a >= 10){a /= 10;++m;}
	printf("%.5Lf %lld\n",a, m);
}
ld pi[67], p; ll n;
ld unwork(){
	int len = 0; ld ans = 0; 
	ll x = n - 1; while(x){x >>= 1;++len;}
	for(int i = 0; i < len; ++i) pi[i] = (ld)((n >> (i + 1)) * (1ll << i) + max(n % (1ll << (i + 1)) - (1ll << i) , 0ll)) / n;
	for(int i = 0; i < len; ++i) ans += 2 * pi[i] * (1 - pi[i]) * (1ll << i);
	return ans;
}
ld work(){
	int len = 0, cnt0 = 0; ld ans = 0; ll x = n - 1; 
	while(x){x >>= 1;++len;}
	for(int i = len - 1; i >= 0; --i){
		if((n - 1) & (1ll << i))ans = ans + (ld)(1ll << i) * n;
		else ans = ans + (n - (ld)(1ll << (cnt0 + i))) * (1ll << i), ++cnt0;
	}
	return ans / n;
}	
signed main(){
	scanf("%lld%Lf",&n,&p);
	print(work() * p + unwork() * (1 - p));
	return 0;
}
posted @ 2022-08-10 20:16  Chen_jr  阅读(45)  评论(0编辑  收藏  举报