9.8<2>题解

T1

考场上以为是线段不能重叠,以至于我推了很久都没有结果,样例不是小的没意义,就是大的手玩不出来,然后我就死了

题解告诉我们他是直线,他用了向量来解释,对于方向向量$(a,b)$,这个方向可以做贡献,一个限制就是$gcd(a,b)=1$,然后就是这个方向有几条直线,如果定义一个点$(x,y)$的前驱为$(x-a,y-b)$,后继为$(x+a,y+b)$,那符合条件的直线的数量就是满足前驱在点阵中,后继不在点阵中的点的数量,然后题解就告诉我说

然而他并没有告诉我经过了什么样的计算,我们来理解一下,前面$(n-a){\times}(m-b)$是所有的前驱在点阵中的点的数量,然后就是刨去后继也在点阵中的点的数量,那其实就是一个点找两个前驱,他的两个前驱都在点阵中的点的数量,那肯定就是$(n-2{\times}a){\times}(m-2{\times}b)$,计算这个东西还是需要$O(n^2)$枚举$a$和$b$,$T$又很大,还是过不去,所以说我们选择前缀和优化他,拆成4个前缀和就可以做了,但是,这个毒瘤出题人他卡空间,然后我就不知道怎么办了,然后就是疯狂${\%}{\%}{\%}{\%}{\%}Smily$,我们发现每个前缀和对答案做贡献都可以是独立的所以,我们用一个前缀和,统计一次答案,清一次,就刚好可以卡过去了。。。。

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstdio>
  4 #include<cmath>
  5 #define maxn 4010
  6 #define maxm 10100
  7 #define ll long long
  8 #define mod 1073741824
  9 using namespace std;
 10 struct node{
 11     int n,m;
 12     ll ans;
 13 }q[maxm];
 14 int T,maxxn,maxxm;
 15 ll ans,ls;
 16 int a[maxn][maxn];
 17 bool g[maxn][maxn];
 18 bool gcd(int x,int y)
 19 {
 20     if(x%2==0&&y%2==0)  return 0;
 21     while(1)
 22     {
 23         if(x==1||y==1)  return 1;
 24         if(x==0||y==0)  return 0;
 25         while(x%2==0)  x/=2;
 26         while(y%2==0)  y/=2;
 27         if(x<y)  swap(x,y);
 28         x-=y;
 29     }
 30 }
 31 inline int read()
 32 {
 33     int e=0;  char ch=getchar();
 34     while(ch<'0'||ch>'9')  ch=getchar();
 35     while(ch>='0'&&ch<='9')  {e=(e<<3)+(e<<1)+(ch^48);  ch=getchar();}
 36     return e;
 37 }
 38 int main()
 39 {
 40     T=read();
 41     for(int i=1;i<=T;++i)
 42     {
 43         q[i].n=read();  q[i].m=read();
 44         maxxn=max(maxxn,q[i].n);  maxxm=max(maxxm,q[i].m);
 45     }
 46     for(int i=1;i<=maxxn;++i)//t
 47     {
 48         for(int j=1;j<=maxxm;++j)
 49         {
 50             if(gcd(i,j))  {a[i][j]=1;  g[i][j]=1;}
 51             else  a[i][j]=0;
 52             ls=(a[i-1][j]+a[i][j-1])%mod;
 53             ls=(ls-a[i-1][j-1]+mod)%mod;  ls=(ls+a[i][j])%mod;  a[i][j]=ls;
 54         }
 55     }
 56     for(int o=1;o<=T;++o)
 57     {
 58         ls=(q[o].n*q[o].m)%mod;  ls=(ls*a[q[o].n-1][q[o].m-1])%mod;
 59         q[o].ans=(q[o].ans+ls)%mod;
 60         int i=q[o].n/2,j=q[o].m/2;
 61         ls=(q[o].n*q[o].m)%mod;  ls=(ls*a[i][j])%mod;
 62                 q[o].ans=(q[o].ans-ls+mod)%mod;
 63         q[o].ans=((q[o].ans%mod)+mod)%mod;
 64     }
 65     for(int i=1;i<=maxxn;++i)//b
 66     {
 67         for(int j=1;j<=maxxm;++j)
 68         {
 69             if(g[i][j])  a[i][j]=j;
 70             else  a[i][j]=0;
 71             ls=(a[i-1][j]+a[i][j-1])%mod;
 72             ls=(ls-a[i-1][j-1]+mod)%mod;  ls=(ls+a[i][j])%mod;  a[i][j]=ls;
 73         }
 74     }
 75     for(int o=1;o<=T;++o)
 76     {
 77         ls=(q[o].n*a[q[o].n-1][q[o].m-1])%mod;  q[o].ans=(q[o].ans-ls+mod)%mod;
 78         int i=q[o].n/2,j=q[o].m/2;
 79         ls=(2*q[o].n*a[i][j])%mod;  q[o].ans=(q[o].ans+ls)%mod;
 80         q[o].ans=((q[o].ans%mod)+mod)%mod;
 81     }
 82     for(int i=1;i<=maxxn;++i)//a
 83     {
 84         for(int j=1;j<=maxxm;++j)
 85         {
 86             if(g[i][j])  a[i][j]=i;
 87             else  a[i][j]=0;
 88             ls=(a[i-1][j]+a[i][j-1])%mod;
 89             ls=(ls-a[i-1][j-1]+mod)%mod;  ls=(ls+a[i][j])%mod;  a[i][j]=ls;
 90         }
 91     }
 92     for(int o=1;o<=T;++o)
 93     {
 94         ls=(q[o].m*a[q[o].n-1][q[o].m-1])%mod;  q[o].ans=(q[o].ans-ls+mod)%mod;
 95         int i=q[o].n/2,j=q[o].m/2;
 96         ls=(2*q[o].m*a[i][j])%mod;  q[o].ans=(q[o].ans+ls)%mod;
 97         q[o].ans=((q[o].ans%mod)+mod)%mod;
 98     }
 99     for(int i=1;i<=maxxn;++i)//ab
100     {
101         for(int j=1;j<=maxxm;++j)
102         {
103             if(g[i][j])  a[i][j]=i*j;
104             else  a[i][j]=0;
105             ls=(a[i-1][j]+a[i][j-1])%mod;
106             ls=(ls-a[i-1][j-1]+mod)%mod;  ls=(ls+a[i][j])%mod;  a[i][j]=ls;
107         }
108     }
109     for(int o=1;o<=T;++o)
110     {
111         ls=a[q[o].n-1][q[o].m-1];  q[o].ans=(q[o].ans+ls)%mod;
112         int i=q[o].n/2,j=q[o].m/2;
113         ls=(4*a[i][j])%mod;  q[o].ans=(q[o].ans-ls+mod)%mod;
114         q[o].ans=(q[o].ans*2)%mod;  q[o].ans=(q[o].ans+q[o].n+q[o].m)%mod;
115         q[o].ans=((q[o].ans%mod)+mod)%mod;
116         printf("%lld\n",q[o].ans);
117     }
118     return 0;
119 }    
View Code

T2

这道题有两种解法,一个是点分治,一个是并查集,点分治我显然还没学会,所以就打的并查集的思路

这题的一个难点在于它既要最小点值,又要最大边值和,那我们考虑枚举最小点值,用并查集直接维护边值和,由于我们是枚举的最小点值,所以只需要让边值和最大,那就并查集记录当前并查集中的最长路径长度,以及这个最长路的两个端点,合并并查集的时候几个端点一通乱配就解决了

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #define maxn 100100
  6 #define int long long
  7 #define ll long long
  8 using namespace std;
  9 struct node{
 10     int val,pos;
 11 }v[maxn];
 12 struct NODE{
 13     ll len;
 14     int po[3];
 15 }bcj[maxn];
 16 int T,n,js;
 17 ll ans;
 18 int head[maxn],to[maxn*2],xia[maxn*2],w[maxn*2];
 19 int deep[maxn],pd[maxn],f[maxn],ww[maxn],bh[maxn],fa[maxn][21];
 20 ll sum[maxn];
 21 bool cmp(const node &a,const node &b)
 22 {
 23     return a.val==b.val?a.pos<b.pos:a.val>b.val;
 24 }
 25 void clear()
 26 {
 27     js=0;  ans=0;
 28     memset(head,0,sizeof(head));  memset(pd,0,sizeof(pd));
 29 }
 30 void add(int x,int y,int z)
 31 {
 32     to[++js]=y;  xia[js]=head[x];  w[js]=z;  head[x]=js;
 33 }
 34 void dfs(int x)
 35 {
 36     pd[x]=1;
 37     for(int i=head[x];i;i=xia[i])
 38     {
 39         int ls=to[i];
 40         if(pd[ls])  continue;
 41         deep[ls]=deep[x]+1;  fa[ls][0]=x;  sum[ls]=sum[x]+w[i];
 42         for(int j=1;j<=20;++j)  fa[ls][j]=fa[fa[ls][j-1]][j-1];
 43         dfs(ls);
 44     }
 45 }
 46 int LCA(int x,int y)
 47 {
 48     if(deep[x]<deep[y])  swap(x,y);
 49     for(int i=20;i>=0;--i)
 50         if(deep[fa[x][i]]>=deep[y])  x=fa[x][i];
 51     if(x==y)  return x;
 52     for(int i=20;i>=0;--i)
 53         if(fa[x][i]!=fa[y][i])  {x=fa[x][i];  y=fa[y][i];}
 54     return fa[x][0];
 55 }
 56 int find(int x)
 57 {
 58     if(f[x]!=x)  f[x]=find(f[x]);
 59     return f[x];
 60 }
 61 void merge(int fa,int son)
 62 {
 63     int po1=0,po2=0;  ll lenn=0;
 64     for(int i=1;i<=2;++i)
 65         for(int j=1;j<=2;++j)
 66         {
 67             int lca=LCA(bcj[fa].po[i],bcj[son].po[j]);
 68             ll lslen=sum[bcj[fa].po[i]]-sum[lca]+sum[bcj[son].po[j]]-sum[lca];
 69             if(lslen>lenn)  {po1=bcj[fa].po[i];  po2=bcj[son].po[j];  lenn=lslen;}
 70         }
 71     if(lenn>bcj[fa].len)  {bcj[fa].len=lenn;  bcj[fa].po[1]=po1;  bcj[fa].po[2]=po2;}
 72     if(bcj[fa].len<bcj[son].len)
 73     {
 74         bcj[fa].len=bcj[son].len;
 75         for(int i=1;i<=2;++i)  bcj[fa].po[i]=bcj[son].po[i];
 76     }
 77 }
 78 main()
 79 {
 80     //freopen("b.in","r",stdin);
 81     scanf("%lld",&T);
 82     while(T--)
 83     {
 84         scanf("%lld",&n);  clear();
 85         for(int i=1;i<=n;++i)  {scanf("%lld",&v[i].val);  v[i].pos=i;  ww[i]=v[i].val;}
 86         for(int i=1;i<n;++i)
 87         {
 88             int u,v,w;  scanf("%lld%lld%lld",&u,&v,&w);
 89             add(u,v,w);  add(v,u,w);
 90         }
 91         deep[1]=1;  sum[1]=0;  dfs(1);  sort(v+1,v+n+1,cmp);
 92         for(int i=1;i<=n;++i)
 93         {
 94             bh[v[i].pos]=i;  f[i]=i;
 95             bcj[i].po[1]=i;  bcj[i].po[2]=i;  bcj[i].len=0;
 96         }
 97         for(int i=1;i<=n;++i)
 98         {
 99             int now=v[i].pos;
100             for(int j=head[now];j;j=xia[j])
101             {
102                 int ls=to[j];
103                 if(ww[ls]<ww[now]||(ww[ls]==ww[now]&&bh[ls]>i))  continue;
104                 int ls1=find(f[now]),ls2=find(f[ls]);
105                 f[ls2]=ls1;  merge(ls1,ls2);
106             }
107             ans=max(ans,bcj[now].len*v[i].val);
108         }
109         printf("%lld\n",ans);
110     }
111     return 0;
112 }
View Code

 T3

考试的时候觉得有点像好久好久之前考过的旅馆那道题,但是最终还是没打线段树,本来打了一个优先队列优化,但是因为时间不够,没调出来,我就把几十行的代码删了,打了个暴力,正解还是线段树,考虑维护区间最左边花精,最右边花精,最长的空区间长度,以及最长的空区间长度对应的那个中间的点

对于询问一,直接找1节点对应的答案,也就是$l-1$,$n-r$,$p$先比较长度,长度相同选最靠左的,选过之后把当前位置放上花精,更新线段树

对于询问二,把该位置清空,更新线段树,$update$那一块细节稍多,yy了好久也没yy明白,最后稍颓了一下下代码。。。。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #define maxn 200200
 6 #define maxx 1001000
 7 #define inf 30000000
 8 using namespace std;
 9 struct node{
10     int zuo,you,l,r,mid,p;
11 }a[maxn<<2];
12 int n,m,opt,num;
13 int pos[maxx];
14 inline int read()
15 {
16     int e=0;  char ch=getchar();
17     while(ch<'0'||ch>'9')  ch=getchar();
18     while(ch>='0'&&ch<='9')  {e=(e<<3)+(e<<1)+(ch^48);  ch=getchar();}
19     return e;
20 }
21 void build(int fa,int l,int r)
22 {
23     a[fa].zuo=l;  a[fa].you=r;
24     if(l==r)  return ;
25     int mid=(l+r)>>1;
26     build(2*fa,l,mid);  build(2*fa+1,mid+1,r);
27 }
28 void update(int fa)
29 {
30     if(a[2*fa].l!=0)  a[fa].l=a[2*fa].l;
31     else  a[fa].l=a[2*fa+1].l;
32     if(a[2*fa+1].r!=0)  a[fa].r=a[2*fa+1].r;
33     else  a[fa].r=a[2*fa].r;
34     a[fa].mid=a[2*fa].mid;  a[fa].p=a[2*fa].p;
35     if(a[2*fa].r!=0&&a[2*fa+1].l!=0)
36     {
37         int len=(a[2*fa+1].l-a[2*fa].r)>>1;
38         if(len>a[fa].mid)  {a[fa].mid=len;  a[fa].p=(a[2*fa].r+a[2*fa+1].l)>>1;}
39         if(a[2*fa+1].mid>a[fa].mid)  {a[fa].mid=a[2*fa+1].mid;  a[fa].p=a[2*fa+1].p;}
40     }
41 }
42 void change(int fa,int x,int op)
43 {
44     if(a[fa].zuo==a[fa].you)
45     {
46         if(op==1)  {a[fa].l=a[fa].you;  a[fa].r=a[fa].zuo;}
47         else  {a[fa].l=0;  a[fa].r=0;}
48         return ;
49     }
50     int mid=(a[fa].zuo+a[fa].you)>>1;
51     if(x<=mid)  change(2*fa,x,op);
52     else  change(2*fa+1,x,op);
53     update(fa);
54 }
55 int main()
56 {
57     n=read();  m=read();
58     build(1,1,n);
59     for(int i=1;i<=m;++i)
60     {
61         opt=read();  num=read();
62         if(opt==1)
63         {
64             int MA=0,po;
65             if(a[1].l==0)  {MA=inf;  po=1;}
66             if(a[1].r==0&&MA!=inf)  {MA=inf;  po=n;}
67             if(a[1].l-1>MA)  {MA=a[1].l-1;  po=1;}
68             if(a[1].mid>MA)  {MA=a[1].mid;  po=a[1].p;}
69             if(n-a[1].r>MA)  {MA=n-a[1].r;  po=n;}
70             pos[num]=po;  change(1,po,1);
71             printf("%d\n",pos[num]);
72         }
73         else  change(1,pos[num],0);  pos[num]=0;
74     }
75     return 0;
76 }
View Code
posted @ 2019-10-04 07:30  hzoi_X&R  阅读(198)  评论(0编辑  收藏  举报