A.雅礼集训convex

回滚莫队:莫队时若发现删除、添加中有一个容易操作(O(1)),有一个不容易操作(>O(1))就可以使用这种方法。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long int ll;
  4 typedef long double ld;
  5 const int maxn=150005;
  6 int n,m;
  7 int len,rk[maxn],bel[maxn];
  8 ll ans[maxn];
  9 struct pt
 10 {
 11     ll x,y;
 12     int id;
 13     ld ra;
 14     ll operator*(const pt&A)const
 15     {
 16         return x*A.y-y*A.x;
 17     }
 18     bool operator<(const pt&A)const
 19     {
 20         return ra<A.ra;
 21     }
 22 }a[maxn],b[maxn];
 23 struct query
 24 {
 25     int l,r,id;
 26     bool operator<(const query&A)const
 27     {
 28         return bel[l]==bel[A.l]?r>A.r:bel[l]<bel[A.l];
 29     }
 30 }Q[maxn];
 31 inline void init()
 32 {
 33     for(int i=1;i<=n;++i)
 34         a[i].ra=atan2(a[i].y,a[i].x);
 35     sort(a+1,a+n+1);
 36     for(int i=1;i<=n;++i)
 37         rk[a[i].id]=i;
 38     len=sqrt(n);
 39 }
 40 int tot,head[555];
 41 int pre[maxn],nxt[maxn];
 42 int tmp[maxn];
 43 ll now;
 44 inline ll f(int x,int y)
 45 {
 46     return a[x]*a[y];
 47 }
 48 inline void doPre(int l)
 49 {
 50     now=0;
 51     memset(tmp,0,sizeof(tmp));
 52     memset(pre,0,sizeof(pre));
 53     memset(nxt,0,sizeof(nxt));
 54     for(int i=l;i<=n;++i)
 55         tmp[rk[i]]=i;
 56     int last=0,first=n+1;
 57     for(int i=1;i<=n;++i)
 58         if(tmp[i])
 59         {
 60             if(last)
 61             {
 62                 pre[i]=last;
 63                 nxt[last]=i;
 64                 now+=f(last,i);
 65             }
 66             last=i;
 67             first=min(first,i);
 68         }
 69     pre[first]=last;
 70     nxt[last]=first;
 71     now+=f(last,first);
 72 }
 73 inline void rem(int pos)
 74 {
 75     now-=f(pre[pos],pos)+f(pos,nxt[pos]);
 76     now+=f(pre[pos],nxt[pos]);
 77     nxt[pre[pos]]=nxt[pos];
 78     pre[nxt[pos]]=pre[pos];
 79 }
 80 inline ll ask(int L,int l)
 81 {
 82 //    cout<<"?? "<<L<<" "<<l<<endl;
 83     ll s=now;
 84     for(int i=L;i<l;++i)
 85     {
 86         int pos=rk[i];
 87         s-=f(pre[pos],pos)+f(pos,nxt[pos]);
 88         s+=f(pre[pos],nxt[pos]);
 89         nxt[pre[pos]]=nxt[pos];
 90         pre[nxt[pos]]=pre[pos];
 91     }
 92     for(int i=l-1;i>=L;--i)
 93     {
 94         int pos=rk[i];
 95         nxt[pre[pos]]=pos;
 96         pre[nxt[pos]]=pos;
 97     }
 98     return s;
 99 }
100 inline void solve()
101 {
102     for(int i=1;i<=n;i+=len)
103     {
104         ++tot;
105         bel[i]=tot;
106         head[tot]=i;
107     }
108     for(int i=1;i<=n;++i)
109         if(!bel[i])
110             bel[i]=bel[i-1];
111     sort(Q+1,Q+m+1);
112     int pos=1;
113     for(int i=1;i<=tot;++i)
114     {
115         doPre(head[i]);
116         int r=n;
117         while(bel[Q[pos].l]==i)
118         {
119             while(r>Q[pos].r)
120                 rem(rk[r--]);
121             ans[Q[pos].id]=ask(head[i],Q[pos].l);
122             ++pos;
123         }
124     }
125 }
126 int main()
127 {
128 //    freopen("convex.in","r",stdin);
129 //    freopen("convex.out","w",stdout);
130     scanf("%d%d",&n,&m);
131     for(int i=1;i<=n;++i)
132     {
133         scanf("%lld%lld",&a[i].x,&a[i].y);
134         a[i].id=i;
135     }
136     for(int i=1;i<=m;++i)
137     {
138         scanf("%d%d",&Q[i].l,&Q[i].r);
139         Q[i].id=i;
140     }
141     init();
142     solve();
143     for(int i=1;i<=m;++i)
144         printf("%lld\n",ans[i]);
145     return 0;
146 }
View Code

B.雅礼集训进攻

容斥的想法:枚举最后的可行矩形,计算包含它的矩形个数,按照(-1)^(行数+列数)进行容斥。

但这样没有任何拓展性!这又一次说明了容斥是多么的菜。

直接统计的想法:尝试将难以考虑的整体转化为易于计数的部分。为了计算一个可行矩形的“1”的贡献,我们将其拆成1*1、1*2、2*1、2*2(这个可以重叠)的小矩形。可以发现,对于任何一个矩形,存在1=cnt(1*1)-cnt(1*2)-cnt(2*1)+cnt(2*2)。在所有可行情况中,某个位置上的cnt产生的总贡献是所有能够包含它的矩形的个数(当然,要k次方),而与包含了多少无关

再考虑如何统计包含某个矩形的矩形个数。以1*1的矩形为例,最直接的方法是枚举所有可行的矩形,并把其中的每一个位置都加上1。我们把它差分成左上角加一、右上左下(要偏移一下)减一、右下加一,若我们能算出这个差分数组,就能在平方的复杂度内算出包含某个矩形的矩形个数。

显然加一减一只和((以某个矩形为某一角,包含这个矩形)的矩形个数)有关。栈即可。

  1 #include<bits/stdc++.h>
  2 #define mod 998244353
  3 using namespace std;
  4 typedef long long int ll;
  5 const int maxn=2E3+5;
  6 int n,m,k;
  7 int a[maxn][maxn],sum[maxn][maxn],up[maxn][maxn],down[maxn][maxn];
  8 int tmp[maxn][maxn];
  9 ll ans;
 10 inline ll qpow(ll x,ll y)
 11 {
 12     ll ans=1,base=x;
 13     while(y)
 14     {
 15         if(y&1)
 16             ans=ans*base%mod;
 17         base=base*base%mod;
 18         y>>=1;
 19     }
 20     return ans;
 21 }
 22 inline void init()
 23 {
 24     for(int j=1;j<=m;++j)
 25         for(int i=1;i<=n;++i)
 26             if(a[i][j])
 27                 up[i][j]=up[i-1][j]+1;
 28     for(int j=1;j<=m;++j)
 29         for(int i=n;i>=1;--i)
 30             if(a[i][j])
 31                 down[i][j]=down[i+1][j]+1;
 32 }
 33 int b[maxn],q[maxn];
 34 inline ll get(int dx,int dy)
 35 {
 36     memset(tmp,0,sizeof(tmp));
 37     for(int i=1;i<=n;++i)
 38     {
 39         int sum=0,top=1;
 40         q[top]=m+1;
 41         for(int j=m;j>=1;--j)
 42         {
 43             b[j]=max(0,down[i][j]-dx+1);
 44             while(top&&b[j]<=b[q[top]])
 45             {
 46                 sum-=(q[top-1]-q[top])*b[q[top]];
 47                 --top;
 48             }
 49             sum+=(q[top]-j)*b[j];
 50             q[++top]=j;
 51             tmp[i][j]+=sum-(dy==2?b[j]:0);
 52         }
 53     }
 54     for(int i=1;i<=n;++i)
 55     {
 56         int sum=0,top=1;
 57         q[top]=0;
 58         for(int j=1;j<=m;++j)
 59         {
 60             b[j]=max(0,down[i][j]-dx+1);
 61             while(top&&b[j]<=b[q[top]])
 62             {
 63                 sum-=(q[top]-q[top-1])*b[q[top]];
 64                 --top;
 65             }
 66             sum+=(j-q[top])*b[j];
 67             q[++top]=j;
 68             tmp[i][j-dy+2]-=sum-(dy==2?b[j]:0);
 69         }
 70     }
 71     for(int i=1;i<=n;++i)
 72     {
 73         int sum=0,top=1;
 74         q[top]=m+1;
 75         for(int j=m;j>=1;--j)
 76         {
 77             b[j]=max(0,up[i][j]-dx+1);
 78             while(top&&b[j]<=b[q[top]])
 79             {
 80                 sum-=(q[top-1]-q[top])*b[q[top]];
 81                 --top;
 82             }
 83             sum+=(q[top]-j)*b[j];
 84             q[++top]=j;
 85             tmp[i-dx+2][j]-=sum-(dy==2?b[j]:0);
 86         }
 87     }
 88     for(int i=1;i<=n;++i)
 89     {
 90         int sum=0,top=1;
 91         q[top]=0;
 92         for(int j=1;j<=m;++j)
 93         {
 94             b[j]=max(0,up[i][j]-dx+1);
 95             while(top&&b[j]<=b[q[top]])
 96             {
 97                 sum-=(q[top]-q[top-1])*b[q[top]];
 98                 --top;
 99             }
100             sum+=(j-q[top])*b[j];
101             q[++top]=j;
102             tmp[i-dx+2][j-dy+2]+=sum-(dy==2?b[j]:0);
103         }
104     }
105     for(int i=1;i<=n;++i)
106         for(int j=1;j<=m;++j)
107             tmp[i][j]+=tmp[i-1][j]+tmp[i][j-1]-tmp[i-1][j-1];
108     ll s=0;
109     for(int i=1;i<=n;++i)
110         for(int j=1;j<=m;++j)
111             s+=qpow(tmp[i][j],k);
112     return s;
113 }
114 inline void solve1()
115 {
116     ans=(ans+get(1,1))%mod;
117 }
118 inline void solve2()
119 {
120     ans=(ans-get(1,2))%mod;
121     ans=(ans-get(2,1))%mod;
122 }
123 inline void solve3()
124 {
125     ans=(ans+get(2,2))%mod;
126 }
127 inline void solve()
128 {
129     solve1();
130     solve2();
131     solve3();
132 }
133 int main()
134 {
135     ios::sync_with_stdio(false);
136     cin>>n>>m>>k;
137     for(int i=1;i<=n;++i)
138     {
139         string str;
140         cin>>str;
141         for(int j=0;j<m;++j)
142             a[i][j+1]=str[j]-'0';
143     }
144     init();
145     solve();
146     cout<<(ans%mod+mod)%mod<<endl;
147     return 0;
148 }
View Code

C.雅礼集训string

首先看清题意!

若我们算出了区间[l,r]的答案,那么新添或删去一个字符串相当于从trie树上新添或删去对应位置的字符串,然后统计增量。

发现添加难,删除简单,还是回滚莫队。

注意这里的分块要按串的总长来分。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 typedef long long int ll;
  4 const int maxn=3E5+5;
  5 int n,m,ans[maxn];
  6 ll a[maxn],A,B,C,L,g[maxn];
  7 int len,tot,have[maxn],bel[maxn],tail[maxn],head[maxn],belW[maxn];
  8 char ch[maxn][26];
  9 string str[maxn];
 10 struct query
 11 {
 12     int l,r,id;
 13     bool operator<(const query&A)const
 14     {
 15         return bel[tail[l-1]+1]==bel[tail[A.l-1]+1]?r>A.r:bel[tail[l-1]+1]<bel[tail[A.l-1]+1];
 16     }
 17 }Q[maxn];
 18 inline void insert(string s)
 19 {
 20     int p=0;
 21     for(int i=0;i<s.size();++i)
 22     {
 23         int x=s[i]-'a';
 24         if(!ch[p][x])
 25             ch[p][x]=++tot;
 26         p=ch[p][x];
 27     }
 28 }
 29 inline void init()
 30 {
 31     len=sqrt(tail[n]);
 32     for(int i=1;i<=tail[n];++i)
 33         bel[i]=bel[i-1]+((i-1)%len==0);
 34     sort(Q+1,Q+m+1);
 35 }
 36 inline bool ok(int f,int len)
 37 {
 38     return f?B*f+A*len>=C:0;
 39 }
 40 ll now;
 41 int maxD,tmp[maxn],pre[maxn],nxt[maxn],inS[maxn];
 42 inline ll f(ll x,ll y)
 43 {
 44     return (x-y)*(x-y+1)/2;
 45 }
 46 int top,wait[maxn];
 47 inline void add(string str,int v)
 48 {
 49     int p=0,d=0;
 50     for(int i=0;i<str.size();++i)
 51     {
 52         p=ch[p][str[i]-'a'];
 53         ++d;
 54         int x=ok(have[p],d);
 55         have[p]+=v;
 56         int y=ok(have[p],d);
 57         if(x==1&&y==0)
 58         {
 59             x=g[d];
 60             --inS[x];
 61             if(inS[x]==0)
 62             {
 63                 now-=f(pre[x],x)+f(x,nxt[x]);
 64                 now+=f(pre[x],nxt[x]);
 65                 pre[nxt[x]]=pre[x];
 66                 nxt[pre[x]]=nxt[x];
 67                 wait[++top]=x;
 68             }
 69         }
 70         else if(x==0&&y==1)
 71             ++inS[g[d]];
 72     }
 73 }
 74 inline void bend()
 75 {
 76     while(top)
 77     {
 78         int x=wait[top];
 79         pre[nxt[x]]=x;
 80         nxt[pre[x]]=x;
 81         --top;
 82     }
 83 }
 84 inline void doPre(int l)
 85 {
 86     memset(tmp,0,sizeof(tmp));
 87     memset(inS,0,sizeof(inS));
 88     memset(nxt,0,sizeof(nxt));
 89     memset(pre,0,sizeof(pre));
 90     memset(have,0,sizeof(have));
 91     top=now=0;
 92     for(int i=l;i<=n;++i)
 93     {
 94         int p=0,d=0,v=a[i];
 95         for(int j=0;j<str[i].size();++j)
 96         {
 97             p=ch[p][str[i][j]-'a'];
 98             ++d;
 99             have[p]+=v;
100             if(ok(have[p],d))
101                 tmp[g[d]]=1,++inS[g[d]];
102         }
103     }
104     int last=0;
105     tmp[0]=tmp[maxD+1]=1;
106     for(int i=0;i<=maxD+1;++i)
107         if(tmp[i])
108         {
109             now+=f(last,i);
110             nxt[last]=i;
111             pre[i]=last;
112             last=i;
113         }
114 }
115 inline void solve()
116 {
117     for(int i=tail[n];i>=1;--i)
118         head[bel[i]]=belW[i];
119     int maxx=bel[tail[n]];
120     int pos=1;
121     for(int i=1;i<=maxx;++i)
122     {
123         int r=n;
124         doPre(head[i]);
125         while(bel[tail[Q[pos].l-1]+1]==i)
126         {
127         cout<<"?!?! "<<now<<endl;
128             while(r>Q[pos].r)
129             {
130                 add(str[r],-a[r]);
131                 --r;
132                 top=0;
133             }
134             int l=head[i];
135             ll g=now;
136             while(l<Q[pos].l)
137             {
138                 add(str[l],-a[l]);
139                 ++l;
140             }
141             ans[Q[pos].id]=now;
142             bend();
143             while(l>head[i])
144             {
145                 --l;
146                 add(str[l],a[l]);
147             }
148             now=g;
149             ++pos;
150         }
151     }
152 }
153 ll gcd(ll x,ll y)
154 {
155     return x%y==0?y:gcd(y,x%y);
156 }
157 int main()
158 {
159     freopen("string1.in","r",stdin);
160     ios::sync_with_stdio(false);
161     cin>>n>>A>>B>>C;
162     for(int i=1;i<=n;++i)
163         cin>>a[i];
164     for(int i=1;i<=n;++i)
165     {
166         cin>>str[i];
167         insert(str[i]);
168         maxD=max(maxD,(int)str[i].size());
169         tail[i]=tail[i-1]+str[i].size();
170         for(int j=tail[i-1]+1;j<=tail[i];++j)
171             belW[j]=i;
172     }
173     for(int i=1;i<=maxD;++i)
174         cin>>g[i];
175     cin>>m;
176     for(int i=1;i<=m;++i)
177     {
178         cin>>Q[i].l>>Q[i].r;
179         Q[i].id=i;
180     }
181     init();
182     solve();
183     ll tot=f(0,maxD+1);
184     for(int i=1;i<=m;++i)
185     {
186         ans[i]=tot-ans[i];
187         ll d=gcd(ans[i],tot);
188         cout<<ans[i]/d<<"/"<<tot/d<<endl;
189     }
190     return 0;
191 }
View Code

 

 posted on 2020-10-16 08:23  GreenDuck  阅读(190)  评论(0编辑  收藏  举报