NOIP模拟77
Posted HZOI_LYM
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP模拟77相关的知识,希望对你有一定的参考价值。
T1:
30pts:暴力枚举点对
70pts:考虑O(n)算法,优化枚举点对过程,考虑对于i,如何确定[l,i]区间内maxor
可以按位考虑,求出i二进制下“补位”x,问题转化为判断[l,i]区间与x最大交,
在[l,r]区间枚举过程中利用sum记录所有出现过的二进制位,与x取交即可
100pts:考虑优化70分过程,由于或的性质,可以贪心选择高位,于是问题转化为
固定r,求解maxor,考虑优化上述判断过程,显然方法为二进制考虑,我们
只需要判断[l,r]区间是否存在该二进制位,暴力枚举即可O(log^2w)
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I long long 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It\'s Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 #define memset(name,val,typ,len) memset (name,val,sizeof (typ) * len) 20 #define Mod1(a,b) (a = a + b > mod ? a + b - mod : a + b) 21 #define Mod2(a,b) (a = a - b < 0 ? a - b + mod : a - b) 22 inline I read () { 23 I x(0),y(1); C z(getchar()); 24 while (!isdigit(z)) { if (z == \'-\') y = -1; z = getchar(); } 25 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 26 return x * y; 27 } 28 inline V Max (I &a,I &b) { a = a > b ? a : b; } 29 inline V Min (I &a,I &b) { a = a < b ? a : b; } 30 inline I max (I &a,I &b) { return a > b ? a : b; } 31 inline I min (I &a,I &b) { return a < b ? a : b; } 32 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 33 inline I abs (I &a) { return a >= 0 ? a : -a; } 34 inline P operator + (const P &a,const P &b) { 35 return MP (a.a + b.a,a.b + b.b); 36 } 37 inline P operator - (const P &a,const P &b) { 38 return MP (a.a - b.a,a.b - b.b); 39 } 40 signed main () { 41 FP (maxor.in), FC (maxor.out); 42 I T (read ()); 43 while (T -- ) { 44 B buc[63]; 45 I l (read ()), r (read ()), ans (0); 46 memset (buc,0,B,63); 47 for (I i(0);i < 63; ++ i) { 48 I s (1ll << i); 49 if (s >= l && s <= r) { 50 buc[i] = 1; continue; 51 } 52 for (I j(62);j >= 0; -- j) { 53 if ((s | (1ll << j)) <= r) 54 s |= (1ll << j); 55 if (s >= l && s <= r) { 56 buc[i] = 1; break; 57 } 58 } 59 } 60 for (I i(0);i < 63; ++ i) if (buc[i]) 61 ans |= (1ll << i); 62 printf ("%lld\\n",ans); 63 } 64 }
T2:
50pts:暴力Dfs枚举选择即可
60~70pts:考虑问题实际上是求方案数k / (1 << n) >= p,观察到值域并不大
背包转移方案数即可,需要卡空间
100pts:考虑再次进行优化,考虑上述过程实际上是求区间第k大值使得所有
小于等于k的方案数大于等于(1 << n) * p,在观察数据范围,可以考虑
meet in the middle ,将两侧所有方案数进行记录,二分第k大值,计算
满足条件的方案数进行判断即可
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It\'s Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 #define memset(name,val,typ,len) memset (name,val,sizeof (typ) * len) 20 #define Mod1(a,b) (a = a + b > mod ? a + b - mod : a + b) 21 #define Mod2(a,b) (a = a - b < 0 ? a - b + mod : a - b) 22 D p; 23 LL sch; 24 I n,tot,cnt,ans,tmp1,sigma,a[25],b[1 << 20],c[1 << 20]; 25 inline I read () { 26 I x(0),y(1); C z(getchar()); 27 while (!isdigit(z)) { if (z == \'-\') y = -1; z = getchar(); } 28 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 29 return x * y; 30 } 31 inline V Max (I &a,I b) { a = a > b ? a : b; } 32 inline V Min (I &a,I b) { a = a < b ? a : b; } 33 inline I max (I &a,I &b) { return a > b ? a : b; } 34 inline I min (I &a,I &b) { return a < b ? a : b; } 35 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 36 inline I abs (I &a) { return a >= 0 ? a : -a; } 37 inline P operator + (const P &a,const P &b) { 38 return MP (a.a + b.a,a.b + b.b); 39 } 40 inline P operator - (const P &a,const P &b) { 41 return MP (a.a - b.a,a.b - b.b); 42 } 43 V Dfs1 (I num) { 44 if (num > tmp1) 45 return b[cnt++] = sigma, V (); 46 sigma += a[num], Dfs1 (num + 1), sigma -= a[num]; 47 Dfs1 (num + 1); 48 } 49 signed main () { 50 n = read (); scanf ("%lf",&p); 51 sch = ceil (p * (1ll << n)); 52 tmp1 = n >> 1; ans = INT_MAX; 53 for (I i(1);i <= tmp1; ++ i) 54 a[i] = read (); 55 Dfs1 (1); sort (b,b + cnt); 56 memcpy (c,b,sizeof b); 57 tmp1 = n - tmp1; tot = cnt, cnt = 0; 58 for (I i(1);i <= tmp1; ++ i) 59 a[i] = read (); 60 Dfs1 (1); sort (b,b + cnt); 61 I l (0), r (b[cnt - 1] + c[tot - 1]); 62 while (l < r) { I mid (l + r >> 1); 63 I p1 (0), p2 (tot - 1); LL sum (0); 64 while (p1 < cnt) { 65 while (b[p1] + c[p2] > mid && p2 >= 0) p2 -- ; 66 sum += tot - p2 - 1; p1 ++ ; 67 } 68 (1ll << n) - sum >= sch ? (Min (ans,mid), r = mid) : l = mid + 1; 69 } 70 printf ("%d\\n",ans); 71 }
T3:
计算空间发现bitset刚好,利用bitset判断连通性,枚举中转点,再枚举贡献点即可
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It\'s Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 #define memset(name,val,typ,len) memset (name,val,sizeof (typ) * len) 20 #define Mod1(a,b) (a = a + b > mod ? a + b - mod : a + b) 21 #define Mod2(a,b) (a = a - b < 0 ? a - b + mod : a - b) 22 const I N = 3e4 + 3; 23 I n,m,t,w[N]; 24 LL MA(-1); 25 LL sum; 26 vector <I> to[N]; 27 vector <bitset <N>> s; 28 inline I read () { 29 I x(0),y(1); C z(getchar()); 30 while (!isdigit(z)) { if (z == \'-\') y = -1; z = getchar(); } 31 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 32 return x * y; 33 } 34 inline V Max (LL &a,LL b) { a = a > b ? a : b; } 35 inline V Min (I &a,I b) { a = a < b ? a : b; } 36 inline I max (I &a,I &b) { return a > b ? a : b; } 37 inline I min (I &a,I &b) { return a < b ? a : b; } 38 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 39 inline I abs (I &a) { return a >= 0 ? a : -a; } 40 inline P operator + (const P &a,const P &b) { 41 return MP (a.a + b.a,a.b + b.b); 42 } 43 inline P operator - (const P &a,const P &b) { 44 return MP (a.a - b.a,a.b - b.b); 45 } 46 signed main () { 47 FP (link.in), FC (link.out); 48 n = read (), m = read (), t = read (); 49 s.resize (n + 1); 50 for (I i(1);i <= m; ++ i) { 51 I x (read ()), y (read ()); 52 s[x][y] = s[y][x] = 1; 53 to[x].push_back (y), to[y].push_back (x); 54 } 55 for (I i(1);i <= n; ++ i) w[i] = read (); 56 for (I i(1);i <= n; ++ i) 57 for (I j(0);j < to[i].size (); ++ j) 58 for (I k(j + 1);k < to[i].size (); ++ k) if (!s[to[i][j]][to[i][k]]) 59 Max (MA,1ll * w[to[i][j]] * w[to[i][k]]), sum += w[to[i][j]] * w[to[i][k]]; 60 printf ("%lld\\n%lld\\n",t != 2 ? MA : 0,t != 1 ? sum << 1 : 0); 61 }
T4:
70pts:bitset暴力维护区间关系即可
100pts:题目关键信息之一为每个原件只参与一次融合,因此可以想到树形结构,
问题转化为判断两点树上关系,首先若无祖先关系puts (0)即可
考虑若y为x祖先,那么满足条件为x到y路径上只存在或运算
反之,为y到x路径上只存在与运算,考虑如何维护
首先只需要判断祖先关系,于是可以利用dfn序进行判断,区间是否有交即可
(若求具体祖先则只能树剖或倍增进行维护)
考虑如何维护一条链上的操作,树剖+线段树显然是可以的,考虑一种新的维护方法
由于需要维护的是与或关系,考虑使用并查集进行关系维护,分别建立与或并查集
利用信息传递即可
代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define I int 4 #define C char 5 #define B bool 6 #define V void 7 #define D double 8 #define LL long long 9 #define UI unsigned int 10 #define UL unsigned long long 11 #define P pair<I,I> 12 #define MP make_pair 13 #define a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It\'s Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 #define memset(name,val,typ,len) memset (name,val,sizeof (typ) * len) 20 #define Mod1(a,b) (a = a + b > mod ? a + b - mod : a + b) 21 #define Mod2(a,b) (a = a - b < 0 ? a - b + mod : a - b) 22 const I N = 5e5 + 3; 23 I n,m,k,x,y,ban; 24 I tot,head[N],to[N],nxt[N],In[N]; 25 I cnt,dfn[N],size[N]; 26 vector <P> que; 27 inline I read () { 28 I x(0),y(1); C z(getchar()); 29 while (!isdigit(z)) { if (z == \'-\') y = -1; z = getchar(); } 30 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 31 return x * y; 32 } 33 inline V Max (I &a,I &b) { a = a > b ? a : b; } 34 inline V Min (I &a,I &b) { a = a < b ? a : b; } 35 inline I max (I &a,I &b) { return a > b ? a : b; } 36 inline I min (I &a,I &b) { return a < b ? a : b; } 37 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 38 inline I abs (I &a) { return a >= 0 ? a : -a; } 39 inline P operator + (const P &a,const P &b) { 40 return MP (a.a + b.a,a.b +2021.11.18-NOIP模拟信心赛
前言
太蒟蒻了,信心赛打的都快没信心了,giaoT1\\(\\color{green}100\\)题目
T1作为简单的签到题,直接先枚举所有的流量再用dijkstra跑这么多遍就可以了
#include<bits/stdc++.h> #define M 2100 #define N 1100 #define inf 0x7f7f7f7f using namespace std; int n,m,maxx=-15; int first[M],nex[M],to[M],w[M],f[M],tot; int dis[N]; bool vis[N]; priority_queue<pair<int,int> >q; //======================================================= inline int read(){ int p=0,f=1; char c=getchar(); while(!isdigit(c)){if(c==\'-\')f=-1;c=getchar();} while(isdigit(c)){p=p*10+c-\'0\';c=getchar();} return p*f; } //======================================================== inline void add(int x,int y,int z,int q){ nex[++tot]=first[x]; first[x]=tot; to[tot]=y; w[tot]=z; f[tot]=q; } //======================================================== inline void dijkstra(){ for(int x=1;x<=1000;x++){ for(int i=1;i<=n;i++){ dis[i]=inf; vis[i]=0; } q.push(make_pair(0,1)); dis[1]=0; while(!q.empty()){ int u=q.top().second; q.pop(); if(vis[u])continue; vis[u]=1; for(int i=first[u];i;i=nex[i]){ int v=to[i]; if(f[i]<x)continue; if(dis[u]+w[i]<dis[v]){ dis[v]=dis[u]+w[i]; if(!vis[v]){ q.push(make_pair(-dis[v],v)); } } } } if(dis[n]!=inf) maxx=max(maxx,x*1000000/dis[n]); } } //======================================================== int main(){ n=read(),m=read(); int a,b,c,f; for(int i=1;i<=m;i++){ a=read(),b=read(),c=read(),f=read(); add(a,b,c,f); add(b,a,c,f); } dijkstra(); cout<<maxx<<endl; return 0; }
T2\\(\\color{red}0\\)题目
明明第二天比第一题还简单简单我却做不出来一开始在哪里想建图然后\\(bfs\\)然后小样例过了,大样例却挂了
结果直接用一个并查集分成两个集合就好了(有两种牛奶)
#include<bits/stdc++.h> using namespace std; #define N 100010 int n,m; char s[N]; int f[N]; int ans[N]; //===================================================== inline int read(){ int p=0,f=1; char c; while(!isdigit(c)){if(c==\'-\')f=-1;c=getchar();} while(isdigit(c)){p=p*10+c-\'0\';c=getchar();} return p*f; } //====================================================== int gf(int x){ if(x == f[x]) return x; return f[x] = gf(f[x]); } //====================================================== void hb(int x, int y){ f[gf(x)] = gf(y); } //====================================================== int main(){ n=read(),m=read(); scanf("%s",s+1); int x,y; for(int i=1;i<=n;i++)f[i]=i; for(int i=1;i<n;i++){ x=read(),y=read(); if(s[x]==s[y]) hb(x,y); } for(int i=1;i<=m;i++){ char c; x=read(),y=read(),cin>>c; if(gf(x)==gf(y)&&s[x]!=c)ans[i]=0; else ans[i]=1; } for(int i=1;i<=m;i++)cout<<ans[i]; return 0; }
T3\\(\\color{red}0\\)题目
第二题都没做出来自然第三题也做不出来
题意:
求一颗树\\(u\\)到\\(v\\)的路径上有无某颜色的点
先跑一遍dfs,再求出\\(u\\)和\\(v\\)的最近公共祖先,这样就可以得到\\(u\\)和\\(v\\)的路径,然后用结构体和vector存储查询的颜色,最近公共祖先以及该点的编号,
最后再来一遍dfs,这一遍相当于把颜色按照节点的深度进行赋值,然后枚举点因为刚才记录了该点所要查询的颜色以及最近公共祖先,而且\\(u\\)和\\(v\\)都记录了,所以如果该点颜色深度大于最近公共祖先的深度,就说明一定能够经过,就把\\(ans[now.id]=1\\)
第三题代码复杂度\\(O\\)(\\(n\\log n\\))
#include<bits/stdc++.h> using namespace std; const int N = 1e5 + 100,M = 2e5 + 100; const int maxdep=24; int n,m; int first[M],to[M],nex[M],tot; int val[N],dep[N],faz[N][maxdep+1],ans[N]; struct mpair{ int col,top,id; }; vector<mpair> vec[N]; //============================================================== inline int read(){ int p=0,f=1; char c=getchar(); while(!isdigit(c)){if(c==\'-\')f=-1;c=getchar();} while(isdigit(c)){p=p*10+c-\'0\';c=getchar();} return p*f; } //============================================================== inline void add(int x,int y){ nex[++tot]=first[x]; first[x]=tot; to[tot]=y; } //============================================================== void dfs1(int u){ for(int i=1;i<=maxdep;i++)faz[u][i]=faz[faz[u][i-1]][i-1]; for(int i=first[u];i;i=nex[i]){ int v=to[i]; if(v==faz[u][0])continue; dep[v]=dep[u]+1; faz[v][0]=u; dfs1(v); } } //============================================================== inline int lca(int x,int y){ if(dep[x]<dep[y])swap(x,y); for(int i=maxdep;i>=0;i--) if(dep[faz[x][i]]>=dep[y])x=faz[x][i]; if(x==y)return x; for(int i=maxdep;i>=0;i--) if(faz[x][i]!=faz[y][i])x=faz[x][i],y=faz[y][i]; return faz[x][0]; } //============================================================== int tmp[N]; void dfs(int u){ int lst=tmp[val[u]]; tmp[val[u]]=dep[u]; for(int i=0;i<vec[u].size();i++){ mpair now=vec[u][i]; if(tmp[now.col]>=dep[now.top]) ans[now.id]=1; } for(int i=first[u];i;i=nex[i]){ int v=to[i]; if(v==faz[u][0])continue; dfs(v); } tmp[val[u]]=lst; } //============================================================== int main(){ n=read(),m=read(); for(int i=1;i<=n;i++)val[i]=read(); int x,y; for(int i=1;i<n;i++){ x=read(),y=read(); add(x,y); add(y,x); } dfs1(1); int c; for(int i=1;i<=m;i++){ x=read(),y=read(),c=read(); int l=lca(x,y); vec[x].push_back(mpair{c,l,i}); vec[y].push_back(mpair{c,l,i}); } memset(tmp,-1,sizeof(tmp)); dfs(1); for(int i=1;i<=m;i++)cout<<ans[i]; return 0; }
今天就是集训的最后一天了,明天就是NOIP2021了,祝所有的OIer rp++
以上是关于NOIP模拟77的主要内容,如果未能解决你的问题,请参考以下文章