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 }
T1

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 }
T2

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 }
T3

 


 

posted @ 2021-08-14 06:39  keen_z  阅读(35)  评论(0编辑  收藏  举报