Scx117
只一眼,便辽阔了时间。

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\n",((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\n",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\n",ans);
62     return 0;
63 }
View Code

 

posted on 2018-06-08 16:36  Scx117  阅读(241)  评论(0编辑  收藏  举报