• PKUSC订正


    Day1 T2:最大前缀和

    枚举答案集合(不直接枚举答案数,相当于状态的离散化),这个集合成为答案当且仅当存在方案使得答案集合的排列后缀和>=0(如果<0就可以去掉显然更优),答案补集的前缀和<0(不能再延伸)。预处理方案数。最后统计的时候注意要枚举答案子集的第一个元素,它不需要满足后缀和>=0。O(2^n*n)。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int mod=998244353;
     4 typedef long long ll;
     5 const int N=1050000;
     6 int n,Max,a[N],sum[N],f[N],g[N],ans;
     7 void up(int &x,int y){x=((ll)x+y)%mod;}
     8 int main()
     9 {
    10     scanf("%d",&n);
    11     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    12     Max=1<<n;
    13     for (int i=1;i<Max;i++)
    14       for (int j=1;j<=n;j++)
    15         if (i&(1<<(j-1))) up(sum[i],a[j]);
    16     f[0]=1;
    17     for (int i=1;i<Max;i++)//后缀和>=0 
    18       if (sum[i]>=0)
    19       {
    20         for (int j=1;j<=n;j++)
    21           if (i&(1<<(j-1))) up(f[i],f[i^(1<<(j-1))]);
    22       }  
    23     g[0]=1;
    24     for (int i=1;i<Max;i++)//前缀和<0 
    25       if (sum[i]<0)
    26       {
    27           for (int j=1;j<=n;j++)
    28             if (i&(1<<(j-1))) up(g[i],g[i^(1<<(j-1))]);
    29       }
    30     for (int i=1;i<Max;i++) 
    31       for (int j=1;j<=n;j++)
    32           if (i&(1<<(j-1)))
    33             up(ans,(ll)f[i^(1<<(j-1))]*g[i^(Max-1)]%mod*sum[i]%mod);
    34     printf("%d
    ",((ll)ans+mod)%mod);//注意ans有可能是负数! 
    35     return 0;
    36 }
    View Code

    Day2

    T1:星际穿越  贪心+树上倍增 

    要想到肯定贪心走能走的较远点。单调肯定不会让你好好求最短路,建树是一个思路。

    性质:当起点在终点右边时,起点要走到终点,必然只会往右走一步,接下来一直往左走。

    每个点朝能够到达的点中覆盖区间左端点最左的点连边,如果它想要走最远,选择这一点一定最优。

    往右走一步也是类似的道理,一定是往右走能够走到的点中覆盖区间左端点最左的点最优。(具体实现可以按照覆盖区间左端点排序)如果往右再往左两步没有直接往左两步优的话,一定不会往右走。

    如果一步可以走到也一定不会往右。(询问的时候特判一下即可)

    询问的时候对于[1..r]求走到x的距离和。倍增使得x在[1..r]外且l[x]在[1..r]内,分成[1..l[x])和[l[x]..r]两段通过走到当前x再走到终点。预处理一下[1..l[i])到i的距离的和。O((n+q)logn)。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=300005;
     4 int l[N],a[N][25],par[N][25],n,pre[N],q,fa[N],mx,b[N],rt[N];
     5 int getmin(int x,int y)
     6 {
     7   return l[x]<l[y]?x:y;
     8 }
     9 void init()
    10 {
    11   for (int i=1;i<=n;i++) a[i][0]=i;
    12   for (int j=1;j<=20;j++)
    13     for (int i=1;i+(1<<j)-1<=n;i++)
    14       a[i][j]=getmin(a[i][j-1],a[i+(1<<(j-1))][j-1]);
    15 }      
    16 int qry(int l,int r)
    17 {
    18   int len=0;
    19   while ((1<<(len+1))<=r-l+1) len++;
    20   return getmin(a[l][len],a[r-(1<<len)+1][len]);
    21 }
    22 bool cmp(int A,int B) {return l[A]<l[B];}
    23 int calc(int x,int y)//[1..x] to y
    24 {
    25     int ans=0;
    26     if (rt[y]) 
    27     {
    28         if (l[y]<=x) ans+=x-l[y]+1,x=l[y]-1;
    29         y=rt[y];ans+=x;
    30     }
    31     if (!x) return ans;
    32     int sum=0;
    33     for (int i=20;i>=0;i--)//倍增使得l[终点]跳进[1..x] 
    34       if (l[par[y][i]]>x) y=par[y][i],sum+=(1<<i);
    35     if (l[y]>x) y=par[y][0],sum++;
    36     return ans+pre[y]+sum*(l[y]-1)+(sum+1)*(x-l[y]+1);
    37 }
    38 int main()
    39 {
    40   scanf("%d",&n);
    41   for (int i=2;i<=n;i++) scanf("%d",&l[i]);
    42   init();
    43   for (int i=2;i<=n;i++) fa[i]=par[i][0]=qry(l[i],i-1);//找到可以跳到最左边的点作为父亲 
    44   for (int j=1;j<=20;j++)//树上倍增 
    45     for (int i=1;i<=n;i++)
    46       par[i][j]=par[par[i][j-1]][j-1];
    47   
    48   for (int i=1;i<=n;i++) b[i]=i;//处理会向右走一步的情况 
    49   sort(b+1,b+n+1,cmp);
    50   for (int i=1;i<=n;i++)
    51   {
    52         for (int j=mx+1;j<b[i];j++) rt[j]=b[i];
    53         mx=max(mx,b[i]);
    54   }
    55   for (int i=1;i<=n;i++)
    56     if (l[rt[i]]>=l[fa[i]]) rt[i]=0;
    57   for (int i=1;i<=n;i++)//处理前缀和[1..l[i]) to i
    58     if (fa[i]==1) pre[i]=0;else pre[i]=pre[fa[i]]+l[fa[i]]-1+2*(l[i]-l[fa[i]]);
    59   
    60   scanf("%d",&q);
    61   while (q--)
    62   {
    63        int l,r,x;
    64     scanf("%d%d%d",&l,&r,&x);
    65     int a=calc(r,x)-calc(l-1,x),b=r-l+1;
    66     int Gcd=__gcd(a,b);
    67     a/=Gcd;b/=Gcd;printf("%d/%d
    ",a,b);
    68   }
    69   return 0;
    70 }
    View Code

    T2:神仙的游戏

    border相交有循环节的性质。问题是快速检查循环节的合法性。(我都想到bitset了T_T)

    如果循环节长度为len时,对应位置的i,j一个为0一个为1,那么循环节长度为len的因数的都不可行。(有一个部分分给的就是暴力枚举01的位置)

    fft处理对应位置的01是否有冲突,需要多项式平移。枚举当前循环节长度的倍数判断可行。时间复杂度O(nlogn)。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int mod=998244353;
     5 const int root=31;
     6 const int N=2000005;
     7 char s[N];
     8 int _n,l,w[N],pos[N],A[N],B[N],sl;
     9 int ksm(int x,int y)
    10 {
    11     int res=1;
    12     while (y) {if (y&1) res=(ll)res*x%mod; x=(ll)x*x%mod; y>>=1;}
    13     return res;
    14 }
    15 void init(int n)
    16 {
    17     l=0;
    18     while ((1<<l)<=n) l++;
    19     _n=(1<<l);int ww=ksm(root,1<<23-l);
    20     w[0]=1;
    21     for (int i=1;i<_n;i++)
    22       w[i]=(ll)w[i-1]*ww%mod,
    23       pos[i]=(i&1)?pos[i-1]|(1<<(l-1)):pos[i>>1]>>1;
    24 }
    25 void fft(int *a)
    26 {
    27     for (int i=0;i<_n;i++) if (i<pos[i]) swap(a[i],a[pos[i]]);
    28     int len=1,id=_n;
    29     for (int i=0;i<l;i++)
    30     {
    31       int wn=w[id>>=1];
    32       for (int j=0;j<_n;j+=len*2)
    33         for (int k=j,ww=1;k<j+len;k++)
    34         {
    35             int l=a[k],r=(ll)a[k+len]*ww%mod;
    36             a[k]=((ll)l+r)%mod;a[k+len]=((ll)l-r+mod)%mod;
    37             ww=(ll)ww*wn%mod;
    38         }
    39       len<<=1;
    40     } 
    41 }
    42 int main()
    43 {
    44     scanf("%s",s+1);sl=strlen(s+1);
    45     for (int i=1;i<=sl;i++)
    46       if (s[i]=='1') A[i]=1;
    47       else if (s[i]=='0') B[sl-i+1]=1;
    48     init(sl*2+1);fft(A);fft(B);
    49     for (int i=0;i<_n;i++) A[i]=(ll)A[i]*B[i]%mod;
    50     fft(A);reverse(A+1,A+_n);
    51     int inv_n=ksm(_n,mod-2);
    52     for (int i=0;i<_n;i++) A[i]=(ll)A[i]*inv_n%mod;
    53     ll ans=(ll)sl*sl;
    54     for (int i=1;i<sl;i++)
    55     {
    56         int fl=1;
    57         for (int j=i;j<=sl&&fl;j+=i)
    58           fl&=(!A[sl-j+1]&&!A[sl+j+1]);
    59         if (fl) ans^=(ll)(sl-i)*(sl-i);
    60     }
    61     printf("%lld
    ",ans);
    62     return 0;
    63 }
    View Code
  • 相关阅读:
    LeetCode分类专题(五)——动态规划1-子序列
    LeetCode分类专题(四)——双指针和滑动窗口1
    LeetCode分类专题(三)——二分查找1
    消息队列(一)——Kafka概述
    Java多线程(五)——synchronized关键字原理
    Java多线程(四)——volatile关键字原理
    Redis(五)——主从复制、哨兵
    Redis(四)——过期、持久化、事件
    Redis(三)——底层数据结构
    MySQL知识点
  • 原文地址:https://www.cnblogs.com/Scx117/p/9156395.html
Copyright © 2020-2023  润新知