• [考试反思]0415省选模拟71:限制


    奇奇怪怪的一场考试。状态还是有点差。

    一看$T2$这$30000$的数据范围就知道大概可以$n^2$卡过。

    然后纠结了半天到底要想正解还是卡暴力。于是又花了好长时间想正解然而什么都没想出来。

    于是就开始卡暴力,的确卡的挺快的但是细节挂了一处丢了$40pts$。

    在靠后也是除了牛逼以外跑得最快的。然而并没有什么用,$WA$了就没啥好说的。

    结果犹犹豫豫磨磨叽叽等$T2$弄完时间也就不多了。于是$T1/3$只好定位为暴力。

    过程中$T1$的正解在脑中一闪而过然而并没有花时间继续想(也没那个时间了)

    最后$T1$的暴力不明原因$50$挂成$40$。$T3$的$15pts$暴力莫名其妙拿到了$30pts$

    就这样了。就是仨题炸了俩。暴力写的倒是挺全。时间分配炸掉了。

    T1:王子

    大意:$n$点序列,每个点有$A_i,B_i$两种权值,要求每个点选择一种权值满足任意连续$k$个点中至少$P$个$A$权值至少$Q$个$B$权值。最大化权值和。$n le 200$

    数据范围闻上去像网络流的味道

    每个节点代表一个长为$k$的区间然后把这些点串起来,原图里的每个点作为一条边驾在它所对应的最左/右的区间之间。

    无源汇上下界最大费用可行流。带正环,所以只要像你钦定下界一样钦定正边满流,调整度数并建反边就行了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 5555
     4 int n,k,A,B,ans,T,fir[S],l[S],to[S],d[S],v[S],w[S],ec=1,q[S],iq[S],al[S];
     5 void link(int a,int b,int V,int W){l[++ec]=fir[a];fir[a]=ec;to[ec]=b;v[ec]=V;w[ec]=W;}
     6 void con(int a,int b,int V,int W=0){
     7     if(W<=0)link(a,b,V,W),link(b,a,0,-W);
     8     else link(a,b,0,W),link(b,a,V,-W),ans+=W,d[a]++,d[b]--;
     9 }
    10 bool bfs(){
    11     for(int i=1;i<=T;++i)d[i]=-998244353;
    12     for(int h=1,t=1;h<=t;iq[q[h]]=0,++h)for(int i=fir[q[h]];i;i=l[i])if(d[to[i]]<d[q[h]]+w[i]&&v[i]){
    13         d[to[i]]=d[q[h]]+w[i];
    14         if(!iq[to[i]])q[++t]=to[i];
    15     }return d[T]!=-998244353;
    16 }
    17 int dfs(int p,int f){int r=f;
    18     if(p==T)return f; al[p]=1;
    19     for(int i=fir[p];i&&r;i=l[i])if(!al[to[i]]&&d[to[i]]==d[p]+w[i]&&v[i]){
    20         int x=dfs(to[i],min(r,v[i]));
    21         if(!x)d[to[i]]=-998244353;
    22         ans+=w[i]*x; v[i]-=x; v[i^1]+=x; r-=x;
    23     }al[p]=0;return f-r;
    24 }
    25 int main(){
    26     cin>>n>>k>>A>>B; T=n-k+3; d[1]=B; d[T-1]=-B;
    27     for(int i=1,x,e;i<=n;++i)scanf("%d%d",&x,&e),ans+=x,con(min(n-k+2,i+1),max(1,i-k+1),1,e-x);
    28     for(int i=1;i<T-1;++i)con(i,i+1,k-A-B);
    29     for(int i=1;i<T;++i)if(d[i]<0)con(0,i,-d[i]);else con(i,T,d[i]);
    30     while(bfs())dfs(0,n);
    31     cout<<ans<<endl;
    32 }
    View Code

    T2:遇见

    大意:求满足(出现过的数出现次数都是奇数)的子区间个数。$n le 30000$

    暴力卡常直接过。

    我加剪枝了:如果这个数目前出现了偶数次且没有下一次出现则直接跳过。

    然后我还把连续的同一种数压在了一起。就过去了。

    正解的话,随机化,给每种颜色随机一个权值然后问题就是求异或和为$0$的区间个数。

    枚举右端点,考虑权值变化。并不会修改,分块+$trie$就行了。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int a[33333],n,N,Ans;bool nxt[33333];short lst[1000005],cnt[1000005],t[33333];
     4 int main(){
     5     scanf("%d",&n);
     6     for(int i=1;i<=n;++i){
     7         N++;
     8         scanf("%d",&a[N]);
     9         if(a[N]==a[N-1])N--;
    10         else nxt[lst[a[N]]]=1,lst[a[N]]=N;
    11         t[N]++;
    12     }
    13     for(int i=1;i<=N;++i){
    14         register int R=N,z=0,ans=0;
    15         for(int j=i;j<=R;++j){
    16             if(z==0)ans+=cnt[a[j]]?t[j]>>1:t[j]+1>>1;
    17             else if(z==1&&cnt[a[j]]&&(cnt[a[j]]&1)==0)ans+=t[j]+1>>1;
    18             z-=cnt[a[j]]&&(cnt[a[j]]&1)==0;
    19             cnt[a[j]]+=t[j];
    20             z+=(cnt[a[j]]&1)==0;
    21             if(!nxt[j]&&(cnt[a[j]]&1)==0)R=j;
    22         }for(int j=i;j<=R;++j)cnt[a[j]]-=t[j];
    23         for(int j=t[i]&1?1:2;j<=t[i];j+=2)Ans+=ans,ans--;
    24         if(t[i]==1)continue;
    25         t[i]--;ans=z=0;R=N;
    26         for(int j=i;j<=R;++j){
    27             if(z==0)ans+=cnt[a[j]]?t[j]>>1:t[j]+1>>1;
    28             else if(z==1&&cnt[a[j]]&&(cnt[a[j]]&1)==0)ans+=t[j]+1>>1;
    29             z-=cnt[a[j]]&&(cnt[a[j]]&1)==0;
    30             cnt[a[j]]+=t[j];
    31             z+=(cnt[a[j]]&1)==0;
    32             if(!nxt[j]&&(cnt[a[j]]&1)==0)R=j;
    33         }for(int j=i;j<=R;++j)cnt[a[j]]-=t[j];
    34         for(int j=t[i]&1?1:2;j<=t[i];j+=2)Ans+=ans,ans--;
    35     }cout<<Ans<<endl;
    36 }
    View Code

    T3:字符串

    大意:给出$n$个模式串满足其$trie$节点$le 50$,给定匹配串支持以下操作:

    询问子区间$[l,r]$中模式串出现次数和。将子区间$[l,r]$循环赋值为$str$(就是把$str$复制若干遍覆盖$[l,r]$)$|S|,Q,sum |str| le 10^5$

    题目提示的已经很明显了是$AC$自动机。

    区间修改能想到的就是线段树。

    我们对线段树每个节点维护$t[i]$表示在线段树左端点进入之前匹配到$AC$自动机的节点$i$的话那么加入区间的字符串之后会匹配到$t[i]$。

    并且维护$w[i]$表示过程中出现的模式串个数。

    可以拿到没有修改的部分分以及可以暴力修改的部分分。

    然后我们对于每个$str$维护一个$g[a][b][c][d]$表示对于第$a$个修改操作对应的$str$从其第$b$位开始走$2^c$位,最开始从$AC$自动机$d$结点出发最后到了哪里以及贡献

    就可以倍增了。

    为了方便我们把线段树最开始的大小重置为$2$的整次幂,那么这个倍增数据就可以直接得到一个节点的值。

    时间复杂度大约是$O(Qlog n |S|)$这级别的。

    时空都要注意,千万别$vector$。$g$的$a,b$可以压成一维就不用$vector$了。我蠢的一批还写了个内存池。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define S 1<<20
     4 int fail[55],c[55][27],q[55],n,Q,v[55],W[55],pc,rt,mi[S]; char s[S];
     5 int lz[S],w[S][51],t[S][51],len,lp,ans,lend[S],cnt,lenth[S],bit,pool[1<<28],SIZE;
     6 void insert(int&p,int l){
     7     if(!p)p=++pc;
     8     if(!s[l]){v[p]++;return;}
     9     insert(c[p][s[l]-'a'],l+1);
    10 }
    11 struct ST{
    12     int bgv,bge,st1,st2;
    13     int&v(int a,int b,int c){return pool[bgv+a*st1+b*st2+c];}
    14     int&e(int a,int b,int c){return pool[bge+a*st1+b*st2+c];}
    15     void init(){
    16         int l=lenth[++cnt]=strlen(s);
    17         st2=l; st1=l*(pc+1); bgv=SIZE; SIZE+=st1*(bit+1); bge=SIZE; SIZE+=st1*(bit+1);
    18         for(int j=0;j<l;++j)for(int i=1;i<=pc;++i)
    19             v(0,i,j)=c[i][s[j]-'a'],e(0,i,j)=W[v(0,i,j)];
    20         for(int i=1;i<=bit;++i)for(int j=0;j<l;++j)for(int k=1;k<=pc;++k)
    21             v(i,k,j)=v(i-1,v(i-1,k,j),(j+(1<<i-1))%l),
    22             e(i,k,j)=e(i-1,v(i-1,k,j),(j+(1<<i-1))%l)+e(i-1,k,j);
    23     }
    24 }R;vector<ST>st;
    25 #define lc p<<1
    26 #define rc lc|1
    27 #define md (L+R>>1)
    28 void up(int p){for(int i=1;i<=pc;++i)t[p][i]=t[rc][t[lc][i]],w[p][i]=w[lc][i]+w[rc][t[lc][i]];}
    29 void build(int p,int L,int R){
    30     if(L==R){
    31         if(R<=len)for(int i=1;i<=pc;++i)t[p][i]=c[i][s[L]-'a'],w[p][i]=W[c[i][s[L]-'a']];
    32         return;
    33     }build(lc,L,md);build(rc,md+1,R); up(p);
    34 }
    35 void cov(int p,int L,int R,int o){
    36     int B=mi[R-L+1],z=(L-lend[o])%lenth[o]; lz[p]=o;
    37     for(int i=1;i<=pc;++i)t[p][i]=st[o].v(B,i,z),w[p][i]=st[o].e(B,i,z);
    38 }
    39 void down(int p,int L,int R){cov(lc,L,md,lz[p]);cov(rc,md+1,R,lz[p]);lz[p]=0;}
    40 void ask(int l,int r,int p=1,int L=1,int R=n){
    41     if(l<=L&&R<=r){ans+=w[p][lp];lp=t[p][lp];return;}
    42     if(lz[p])down(p,L,R);
    43     if(l<=md)ask(l,r,lc,L,md); if(r>md)ask(l,r,rc,md+1,R);
    44 }
    45 void mdf(int l,int r,int p=1,int L=1,int R=n){
    46     if(l<=L&&R<=r){cov(p,L,R,cnt); return;}
    47     if(lz[p])down(p,L,R);
    48     if(l<=md)mdf(l,r,lc,L,md); if(r>md)mdf(l,r,rc,md+1,R); up(p);
    49 }
    50 int main(){//freopen("ex_string2.in","r",stdin);freopen("0.out","w",stdout);
    51     for(int i=0;i<=19;++i)mi[1<<i]=i;
    52     cin>>n>>Q; st.push_back(R);
    53     for(int i=1;i<=n;++i)cin>>s,insert(rt,0);
    54     q[1]=1; fail[0]=1;
    55     for(int i=0;i<26;++i)c[0][i]=1;
    56     for(int h=1,t=1;h<=t;++h)for(int j=0;j<26;++j)
    57         if(c[q[h]][j])fail[q[++t]=c[q[h]][j]]=c[fail[q[h]]][j];
    58         else c[q[h]][j]=c[fail[q[h]]][j];
    59     for(int i=1;i<=pc;++i)for(int j=i;j;j=fail[j])W[i]+=v[j];
    60     scanf("%s",s+1); len=strlen(s+1);n=1;
    61     while(n<len)n<<=1,bit++; build(1,1,n);
    62     while(Q--){
    63         int op,x,y;scanf("%d%d%d",&op,&x,&y);
    64         if(op==2)lp=1,ans=0,ask(x,y),printf("%d
    ",ans);
    65         else scanf("%s",s),R.init(),st.push_back(R),mdf(lend[cnt]=x,y);
    66     }
    67 }
    View Code
  • 相关阅读:
    每日Linux命令不完整命令
    mysql安装
    自动调用杀毒软件对文件进行杀毒
    正则获得字符串数组,以字符串分隔获取
    利用SQL语句查找某数据库中所有存储过程包含的内容
    TextBox的滚动条自动到最底部、利用枚举获取HashTable中的值
    Ajax中如何使用Session变量,Cookies可以用表单验证的方式获取并使用。
    用SQL语句批量生成一个表的INSERT语句
    利用DataSet、DataTable、DataView按照自定义条件过滤数据
    向线程传递数据与线程用回调方法检索数据
  • 原文地址:https://www.cnblogs.com/hzoi-DeepinC/p/12709014.html
Copyright © 2020-2023  润新知