2021.8.13考试总结[NOIP模拟38]
T1 a
入阵曲。枚举矩形上下界,之后从左到右扫一遍。用树状数组维护前缀和加特判可以$A$,更保险要脸的做法是双指针扫,因为前缀和单调不减。
$code:$
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define rin register signed 4 using namespace std; 5 const int NN=5e4+5; 6 int n,m,l,r,mat[35][NN],pre[35][NN],ext; 7 LL ans; 8 char zo[NN]; 9 bool jz,jo,skip; 10 inline int read(){ 11 int x=0,f=1; char ch=getchar(); 12 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 13 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 14 return x*f; 15 } 16 inline void write(LL x,char sp){ 17 char ch[20]; int len=0; 18 if(x<0){ putchar('-'); x=~x+1; } 19 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 20 for(rin i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 21 } 22 struct tree_array{ 23 int c[35*NN]; 24 inline int lowbit(int x){ return x&(-x); } 25 inline void insert(int pos){ 26 while(pos<=max(r,pre[n][m]+1)){ 27 c[pos]++; 28 pos+=lowbit(pos); 29 } 30 } 31 inline int query(int pos){ 32 int res=0; 33 while(pos>0){ 34 res+=c[pos]; 35 pos-=lowbit(pos); 36 } 37 return res; 38 } 39 inline void clear(int pos){ 40 while(pos<=max(r,pre[n][m]+1)){ 41 if(!c[pos]) break; 42 c[pos]=0; 43 pos+=lowbit(pos); 44 } 45 } 46 }t; 47 void spj(){ 48 if(!jo){ puts("0"); skip=1; return; } 49 if(l==0&&r==m*n){ 50 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) 51 ans+=(n-i+1)*(m-j+1); 52 write(ans,'\n'); skip=1; 53 return; 54 } 55 if(!jz){ 56 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) 57 if(i*j>=l&&i*j<=r) ans+=(n-i+1)*(m-j+1); 58 write(ans,'\n'); skip=1; 59 return; 60 } 61 } 62 signed main(){ 63 n=read(); m=read(); 64 for(rin i=1;i<=n;i++){ 65 scanf("%s",zo+1); 66 for(rin j=1;j<=m;j++){ 67 mat[i][j]=(zo[j]=='1'); 68 if(mat[i][j]) jo=1; 69 if(!mat[i][j]) jz=1; 70 pre[i][j]=pre[i][j-1]+mat[i][j]; 71 } 72 for(rin j=1;j<=m;j++) pre[i][j]+=pre[i-1][j]; 73 } 74 l=read(); r=read(); 75 spj(); if(skip) return 0; 76 for(rin i=0;i<n;i++) for(rin j=i+1;j<=n;j++){ 77 for(rin k=1;k<=m;k++){ 78 int res=pre[j][k]-pre[i][k]+1; 79 ans+=t.query(res-l)-t.query(res-r-1); 80 t.insert(res); 81 } 82 ans+=t.query(r+1)-t.query(l); 83 for(rin k=1;k<=m;k++) t.clear(pre[j][k]-pre[i][k]+1); 84 } 85 write(ans,'\n'); 86 return 0; 87 }
T2 b
单独考虑每个$gcd$的贡献,问题转化为求每个$gcd$的方案数。
值域只有$1e5$,可以直接约数分解,统计每行中有几个$j$的倍数,记为$cnt_{i,j}$。
对每个$i$,令最终$gcd$为$i$的倍数的方案为$(\prod_{i=1}^{i\leq n}(cnt_{i,j}+1))-1$。
之后容斥求出最终$gcd$为$i$的方案数即可。
$code:$
1 #include<bits/stdc++.h> 2 #define int long long 3 using namespace std; 4 const int NN=1e5+5,p=1e9+7; 5 int a[21][NN],n,m,ans,cnt[21][NN],sum[NN]; 6 vector<int>vec[NN]; 7 inline int read(){ 8 int x=0,f=1; char ch=getchar(); 9 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 10 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 11 return x*f; 12 } 13 inline void write(int x,char sp){ 14 char ch[20]; int len=0; 15 if(x<0){ putchar('-'); x=~x+1; } 16 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 17 for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 18 } 19 signed main(){ 20 n=read(); m=read(); 21 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) 22 a[i][j]=read(), vec[a[i][j]].push_back(i); 23 for(int i=1e5,sq,ext;i;i--) if(vec[i].size()){ 24 sq=sqrt(i); ext=vec[i].size(); 25 for(int j=1;j<=sq;j++) if(!(i%j)) 26 for(int k=0;k<ext;k++){ 27 ++cnt[vec[i][k]][j]; 28 if(j*j!=i) ++cnt[vec[i][k]][i/j]; 29 } 30 } 31 for(int i=1;i<=1e5;i++){ 32 sum[i]=1; 33 for(int j=1;j<=n;j++) (sum[i]*=(cnt[j][i]+1))%=p; 34 sum[i]=(sum[i]-1+p)%p; 35 } 36 for(int i=1e5;i;i--){ 37 int tmp=i<<1; 38 while(tmp<=1e5){ sum[i]=(sum[i]-sum[tmp]+p)%p; tmp+=i; } 39 (ans+=sum[i]*i%p)%=p; 40 } 41 write(ans,'\n'); 42 return 0; 43 }
T3 c
最小环长度不超过二,其实就是树上有一些重边。发现对于多种颜色重边,只剩下三种不同颜色即可。
点分治,$DP$。建出点分树后将问题转化到$x$,$y$在点分树上的$LCA$上。
设$f_{i,j,k}$表示$i$到当前重心路径上重心端边颜色为$j$,$i$端边颜色为$k$的方案。
$DFS$时记$son_i$为$i$到重心路径中重心的儿子,用于更新答案。
具体见代码。应该很好理解。
$code:$
1 #include<bits/stdc++.h> 2 #define x first 3 #define y second 4 #define pb push_back 5 #define mp make_pair 6 using namespace std; 7 typedef pair<int,int> ii; 8 typedef vector<int> vi; 9 const int NN=2e5+5; 10 struct node{ int id,x,y; }; 11 int n,m,q,S,root,ans[NN],f[NN][3][3],dep[NN],fa[NN][20],wt[NN],siz[NN],son[NN]; 12 bool vis[NN]; 13 vector<ii>vec[NN]; 14 vector<int>col[NN]; 15 vector<pair<int,vector<int> > >e[NN]; 16 vector<node>ask[NN]; 17 inline int read(){ 18 int x=0,f=1; char ch=getchar(); 19 while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } 20 while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } 21 return x*f; 22 } 23 inline void write(int x,char sp){ 24 char ch[25]; int len=0; 25 if(x<0){ putchar('-'); x=~x+1; } 26 do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x); 27 for(int i=len-1;~i;i--) putchar(ch[i]); putchar(sp); 28 } 29 void dfa(int s,int fa){ 30 sort(vec[s].begin(),vec[s].end()); 31 vec[s].erase(unique(vec[s].begin(),vec[s].end()),vec[s].end()); 32 for(int i=0,j;i<vec[s].size();i=j){ 33 int v=vec[s][i].x; 34 j=i+1; 35 while(j<vec[s].size()&&vec[s][j].x==v) j++; 36 if(v==fa) continue; 37 e[s].pb(mp(v,vector<int>())); 38 e[v].pb(mp(s,vector<int>())); 39 for(int k=i;k<j&&k<i+3;k++){ 40 e[s].back().y.pb(vec[s][k].y); 41 e[v].back().y.pb(vec[s][k].y); 42 } 43 dfa(v,s); 44 } 45 } 46 void getroot(int s,int ff){ 47 siz[s]=1; wt[s]=0; 48 for(int i=0;i<e[s].size();i++){ 49 int v=e[s][i].x; 50 if(v==ff||vis[v]) continue; 51 getroot(v,s); 52 siz[s]+=siz[v]; 53 wt[s]=max(wt[s],siz[v]); 54 } 55 wt[s]=max(wt[s],S-siz[s]); 56 if(wt[s]<wt[root]) root=s; 57 } 58 void build(int s,int ff){ 59 fa[s][0]=ff; vis[s]=1; dep[s]=dep[ff]+1; 60 for(int i=1;i<20;i++) 61 fa[s][i]=fa[fa[s][i-1]][i-1]; 62 for(int i=0;i<e[s].size();i++){ 63 int v=e[s][i].x; 64 if(vis[v]) continue; 65 wt[root=0]=1e9; S=siz[v]; 66 getroot(v,0); 67 build(root,s); 68 } 69 } 70 inline int LCA(int x,int y){ 71 if(dep[x]>dep[y]) swap(x,y); 72 for(int i=19;~i;i--) 73 if(dep[fa[y][i]]>=dep[x]) y=fa[y][i]; 74 if(x==y) return x; 75 for(int i=19;~i;i--) 76 if(fa[x][i]!=fa[y][i]) x=fa[x][i], y=fa[y][i]; 77 return fa[x][0]; 78 } 79 void dfs(int s,int ff,int rtson){ 80 son[s]=rtson; 81 for(int i=0;i<e[s].size();i++){ 82 int v=e[s][i].x; 83 if(v==ff||vis[v]) continue; 84 col[v]=e[s][i].y; 85 for(int j=0;j<col[rtson].size();j++) 86 for(int k=0;k<col[v].size();k++){ 87 f[v][j][k]=-1e9; 88 for(int l=0;l<col[s].size();l++) 89 f[v][j][k]=max(f[v][j][k],f[s][j][l]+(col[s][l]!=col[v][k])); 90 } 91 dfs(v,s,rtson); 92 } 93 } 94 void calc(int s){ 95 vis[s]=1; 96 for(int i=0;i<e[s].size();i++){ 97 int v=e[s][i].x; 98 if(vis[v]) continue; 99 col[v]=e[s][i].y; 100 for(int j=0;j<col[v].size();j++) 101 for(int k=0;k<col[v].size();k++) 102 f[v][j][k]=(j==k)?1:-1e9; 103 dfs(v,s,v); 104 } 105 for(int i=0;i<ask[s].size();i++){ 106 int x=ask[s][i].x,y=ask[s][i].y,id=ask[s][i].id; 107 if(y==s) swap(x,y); 108 if(x==y) ans[id]=0; 109 else if(x==s) 110 for(int j=0;j<col[son[y]].size();j++) 111 for(int k=0;k<col[y].size();k++) 112 ans[id]=max(ans[id],f[y][j][k]); 113 else 114 for(int j=0;j<col[son[x]].size();j++) 115 for(int k=0;k<col[son[y]].size();k++) 116 for(int l=0;l<col[x].size();l++) 117 for(int o=0;o<col[y].size();o++) 118 ans[id]=max(ans[id],f[x][j][l]+f[y][k][o]-(col[son[x]][j]==col[son[y]][k])); 119 } 120 for(int i=0;i<e[s].size();i++){ 121 int v=e[s][i].x; 122 if(vis[v]) continue; 123 S=siz[v]; wt[root=0]=1e9; 124 getroot(v,0);calc(root); 125 } 126 } 127 signed main(){ 128 n=read(); m=read(); 129 for(int i=1,u,v,w;i<=m;i++){ 130 u=read(); v=read(); w=read(); 131 vec[u].pb(mp(v,w)); vec[v].pb(mp(u,w)); 132 } 133 dfa(1,0); 134 wt[root=0]=S=n; 135 getroot(1,0); build(root,0); 136 q=read(); 137 for(int i=1;i<=q;i++){ 138 int x=read(),y=read(); 139 ask[LCA(x,y)].pb((node){i,x,y}); 140 } 141 memset(vis,0,sizeof(vis)); 142 wt[root=0]=S=n; 143 getroot(1,0); 144 calc(root); 145 for(int i=1;i<=q;i++) write(ans[i],'\n'); 146 return 0; 147 }