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题
以及\(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;
}