zoukankan      html  css  js  c++  java
  • NOIP2018训练题集

    1. CZday3C

    给定有m个数的集合,从其中任选一个子集满足全部&后不为零,问方案数。

    考虑对二进制位容斥,问题转化为求包含某个二进制位集合的数的个数,通过类似FMT的DP求解。

     1 #include<bits/stdc++.h>
     2 #define mo 1000000007
     3 #define ll long long
     4 using namespace std;
     5 ll m,n,k,f[1100010],g[1100010],x,ans;
     6 ll po(ll x,ll y){ll z=1;while (y){if (y%2==1)z=(x*z)%mo;x=(x*x)%mo;y/=2;}return z;}
     7 int main(){
     8     freopen("loneliness.in","r",stdin);
     9     freopen("loneliness.out","w",stdout);
    10     cin>>n;
    11     cin>>n>>m>>k;
    12     for (int i=1;i<=m;i++){scanf("%d",&x);g[x]++;}
    13     f[0]=-1;
    14     for (int i=0;i<(1<<n);i++)
    15         for (int j=1;j<(1<<n);j*=2)
    16             if ((i&j)==0)f[i+j]=f[i]*(-1);
    17     for (int i=1;i<(1<<n);i*=2)
    18         for (int j=0;j<(1<<n);j++)
    19             if ((i&j)!=0) g[j-i]+=g[j];
    20     for (int i=1;i<(1<<n);i++)ans=(ans+f[i]*po(g[i],k)+mo)%mo;
    21     cout<<ans<<endl;
    22     return 0;
    23 }
    View Code

    2.CZday6C

    在线修改,查询第一个比前面所有数之和大的数。

    类似FRBSUM,如果一个数不是答案,则下一个答案必然不小于从头一直加到这个数的和,这样倍增查询每次至少翻倍,线段树支持即可。

     1 #include<bits/stdc++.h>
     2 #define maxn 200010
     3 #define N 800010
     4 #define ll long long
     5 using namespace std;
     6 int value[maxn], mx[N];
     7 ll sum[N];
     8 void build(int now, int l, int r)
     9 {
    10     if (l == r)
    11     {
    12         mx[now] = sum[now] = value[l];
    13         return;
    14     }
    15     int mid = (l + r) / 2;
    16     build(now * 2, l, mid);
    17     build(now * 2 + 1, mid + 1, r);
    18     mx[now] = max(mx[now * 2], mx[now * 2 + 1]);
    19     sum[now] = sum[now * 2] + sum[now * 2 + 1];
    20 }
    21 void modify(int now, int l, int r, int x, int y)
    22 {
    23     if (l == r)
    24     {
    25         mx[now] = sum[now] = value[l];
    26         return;
    27     }
    28     int mid = (l + r) / 2;
    29     if (x <= mid) modify(now * 2, l, mid, x, y);
    30     else modify(now * 2 + 1, mid + 1, r, x, y);
    31     mx[now] = max(mx[now * 2], mx[now * 2 + 1]);
    32     sum[now] = sum[now * 2] + sum[now * 2 + 1];
    33 }
    34 ll query_sum(int now, int l, int r, int left, int right)
    35 {
    36     if (l == left && r == right) return sum[now];
    37     int mid = (l + r) / 2; ll ans = 0;
    38     if (left <= mid) ans = query_sum(now * 2, l, mid, left, min(right, mid));
    39     if (right >= mid + 1) ans += query_sum(now * 2 + 1, mid + 1, r, max(left, mid + 1), right);
    40     return ans;
    41 }
    42 int query(int now, int l, int r, int left, int right, ll x)
    43 {
    44     int mid = (l + r) / 2;
    45     if (l == left && r == right)
    46     {
    47         if (mx[now] < x) return -1;
    48         if (l == r) return l;
    49         if (mx[now * 2] >= x) return query(now * 2, l, mid, l, mid, x);
    50         else return query(now * 2 + 1, mid + 1, r, mid + 1, r, x);
    51     }
    52     int ans = -1;
    53     if (left <= mid) ans = query(now * 2, l, mid, left, min(right, mid), x);
    54     if (ans != -1) return ans;
    55     else return query(now * 2 + 1, mid + 1, r, max(left, mid + 1), right, x);
    56 }
    57 int main()
    58 {
    59     freopen("challenge.in", "r", stdin);
    60     freopen("challenge.out", "w", stdout);
    61     int n, q;
    62     scanf("%d%d", &n, &q);
    63     for (int i = 1; i <= n; i++)
    64         scanf("%d", &value[i]);
    65     build(1, 1, n);
    66     for (int i = 1; i <= q; i++)
    67     {
    68         int x, y;
    69         scanf("%d%d", &x, &y);
    70         value[x] = y;
    71         modify(1, 1, n, x, y);
    72         int cur = 0, res = -1; ll pre = 0;
    73         while (cur < n)
    74         {
    75             int tmp = query(1, 1, n, cur + 1, n, pre);
    76             if (tmp == -1) break;
    77             cur = tmp; pre = query_sum(1, 1, n, 1, tmp);
    78             if (pre - value[cur] == value[cur]) {res = tmp; break;}
    79         }
    80         printf("%d
    ", res);
    81     }
    82     return 0;
    83 }
    View Code

    3.ACday3C

    n个数,m个等级(m<=10),某个数不小于某值ai就是i级。在线区间加,单点修改,询问区间所有数等级和。

    线段树,Min[x]表示这个区间中最小的离下一级的距离。更新时如果Min[x]>0则退出,否则递归下去。均摊复杂度nmlogn。类似区间开方之类的线段树均摊操作。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define ls (x<<1)
     4 #define rs (ls|1)
     5 #define lson ls,L,mid
     6 #define rson rs,mid+1,R
     7 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     8 using namespace std;
     9 
    10 const int N=500010;
    11 int n,m,Q,op,x,y,k,a[12],c[N],sm[N],mn[N],tag[N];
    12 
    13 int chk(int v){ for (int i=m; ~i; i--) if (v>=a[i]) return i; return 0; }
    14 void upd(int x){ sm[x]=sm[ls]+sm[rs]; mn[x]=min(mn[ls],mn[rs]); }
    15 
    16 void push(int x){
    17     if (!tag[x]) return;
    18     mn[ls]+=tag[x]; tag[ls]+=tag[x];
    19     mn[rs]+=tag[x]; tag[rs]+=tag[x];
    20     tag[x]=0;
    21 }
    22 
    23 void build(int x,int L,int R){
    24     if (L==R){ sm[x]=chk(c[L]); mn[x]=a[sm[x]+1]-c[L]; return; }
    25     int mid=(L+R)>>1;
    26     build(lson); build(rson); upd(x);
    27 }
    28 
    29 void work(int x,int L,int R){
    30     if (mn[x]>0) return;
    31     if (L==R){
    32         while (mn[x]<=0) sm[x]++,mn[x]=a[sm[x]+1]-a[sm[x]]+mn[x];
    33         return;
    34     }
    35     push(x); int mid=(L+R)>>1;
    36     work(lson); work(rson); upd(x);
    37 }
    38 
    39 void add(int x,int L,int R,int l,int r,int k){
    40     if (L==l && r==R){ mn[x]-=k; tag[x]-=k; work(x,L,R); return; }
    41     push(x); int mid=(L+R)>>1;
    42     if (r<=mid) add(lson,l,r,k);
    43     else if (l>mid) add(rson,l,r,k);
    44         else add(lson,l,mid,k),add(rson,mid+1,r,k);
    45     upd(x);
    46 }
    47 
    48 void mdf(int x,int L,int R,int pos,int k){
    49     if (L==R){ sm[x]=chk(k); mn[x]=a[sm[x]+1]-k; return; }
    50     push(x); int mid=(L+R)>>1;
    51     if (pos<=mid) mdf(lson,pos,k); else mdf(rson,pos,k);
    52     upd(x);
    53 }
    54 
    55 int que(int x,int L,int R,int l,int r){
    56     if (L==l && r==R) return sm[x];
    57     push(x); int mid=(L+R)>>1;
    58     if (r<=mid) return que(lson,l,r);
    59     else if (l>mid) return que(rson,l,r);
    60         else return que(lson,l,mid)+que(rson,mid+1,r);
    61 }
    62 
    63 int main(){
    64     scanf("%d%d%d",&n,&m,&Q);
    65     rep(i,1,m) scanf("%d",&a[i]);
    66     a[0]=-2e9; a[m+1]=2e9;
    67     rep(i,1,n) scanf("%d",&c[i]);
    68     build(1,1,n);
    69     while (Q--){
    70         scanf("%d%d%d",&op,&x,&y);
    71         if (op==1) scanf("%d",&k),add(1,1,n,x,y,k);
    72         else if (op==2) mdf(1,1,n,x,y);
    73             else printf("%d
    ",que(1,1,n,x,y));
    74     }
    75     return 0;
    76 }
    View Code

    4.ACday4C

    一棵树和一些边,在线询问只取[L,R]中的边时,S到T的边权异或和最小的路径。

    非常好的一道题,发现一条边的贡献一定是和树边组成的环的异或和,线性基加优化求解。

    http://noi.ac/contest/13/problem/41

    https://www.cnblogs.com/Gloid/p/9658421.html

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     6 using namespace std;
     7 
     8 const int N=300010;
     9 struct Que{ int id,s,l,r; }q[N],q1[N];
    10 int n,m,Q,u,v,w,S,T,l,r,cnt,dep[N],d[N],ans[N],h[N],to[N<<1],val[N<<1],nxt[N<<1];
    11 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
    12 
    13 struct B{
    14     int d[32];
    15     B (){ memset(d,0,sizeof(d)); }
    16     void ins(int x){
    17         for (int i=30; ~i; i--)
    18             if (x&(1<<i)){
    19                 if (!d[i]) { d[i]=x; break; } else x^=d[i];
    20             }
    21     }
    22 }suf[N],pre[N];
    23 
    24 B operator +(const B &a,const B &b){
    25     B c;
    26     for (int i=30; ~i; i--) c.d[i]=a.d[i];
    27     rep(i,0,30) if (b.d[i]) c.ins(b.d[i]);
    28     return c;
    29 }
    30 
    31 void dfs(int x,int fa){
    32     For(i,x) if ((k=to[i])!=fa) dep[k]=dep[x]^val[i],dfs(k,x);
    33 }
    34 
    35 int work(int x,const B &a){ for (int i=30; ~i; i--) x=min(x,x^a.d[i]); return x; }
    36 
    37 void solve(int l,int r,int low,int high){
    38     if (l>r || low>high) return;
    39     if (low==high){ rep(i,l,r) ans[q[i].id]=min(q[i].s,q[i].s^d[low]); return; }
    40     int mid=(low+high)>>1,st=l-1,ed=r+1;
    41     for (int i=mid; i>=low; i--){
    42         if (i==mid) pre[i]=pre[0]; else pre[i]=pre[i+1];
    43         pre[i].ins(d[i]);
    44     }
    45     rep(i,mid,high){
    46         if (i==mid+1) suf[i]=suf[0]; else suf[i]=suf[i-1];
    47         suf[i].ins(d[i]);
    48     }
    49     rep(i,l,r)
    50         if (q[i].l<=mid && q[i].r>mid) ans[q[i].id]=work(q[i].s,pre[q[i].l]+suf[q[i].r]);
    51         else if (q[i].r<=mid) q1[++st]=q[i]; else q1[--ed]=q[i];
    52     rep(i,l,r) q[i]=q1[i];
    53     solve(l,st,low,mid); solve(ed,r,mid+1,high);
    54 }
    55 
    56 int main(){
    57     scanf("%d%d%d",&n,&m,&Q);
    58     rep(i,2,n) scanf("%d%d%d",&u,&v,&w),add(u,v,w),add(v,u,w);
    59     dfs(1,0);
    60     rep(i,1,m) scanf("%d%d%d",&u,&v,&w),d[i]=dep[u]^dep[v]^w;
    61     rep(i,1,Q) scanf("%d%d%d%d",&S,&T,&l,&r),q[i]=(Que){i,dep[S]^dep[T],l,r};
    62     solve(1,Q,1,m);
    63     rep(i,1,Q) printf("%d
    ",ans[i]);
    64     return 0;
    65 }
    View Code

    5.NOWday1C

    一棵树一些路径,每次询问一个点vi的最远祖先u,满足uv之间的路径被至少ki条路径完全包含。

    可以DFS化成二维数点问题主席树和倍增解决,也可以每个点记录子树内最远的一个是某个路径拐点(LCA)的祖先,线段树合并即可。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #define lson ls[x],L,mid
     6 #define rson rs[x],mid+1,R
     7 #define rep(i,l,r) for (int i=l; i<=r; i++)
     8 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     9 typedef long long ll;
    10 using namespace std;
    11  
    12 const int N=200010;
    13 int n,m,u,v,k,l,cnt,nd,Q,rt[N],fa[N][19],dep[N];
    14 int h[N],nxt[N<<1],to[N<<1],sz[N*80],ls[N*80],rs[N*80];
    15 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    16  
    17 void dfs(int x){
    18     dep[x]=dep[fa[x][0]]+1;
    19     rep(i,1,18) fa[x][i]=fa[fa[x][i-1]][i-1];
    20     For(i,x) if ((k=to[i])!=fa[x][0]) fa[k][0]=x,dfs(k);
    21 }
    22  
    23 int lca(int u,int v){
    24     if (dep[u]<dep[v]) swap(u,v);
    25     int t=dep[u]-dep[v];
    26     for (int i=18; ~i; i--) if (t&(1<<i)) u=fa[u][i];
    27     if (u==v) return u;
    28     for (int i=18; ~i; i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    29     return fa[u][0];
    30 }
    31  
    32 void ins(int &x,int L,int R,int k){
    33     if (!x) x=++nd; sz[x]++;
    34     if (L==R) return;
    35     int mid=(L+R)>>1;
    36     if (k<=mid) ins(lson,k); else ins(rson,k);
    37 }
    38  
    39 int merge(int x,int y){
    40     if (!x || !y) return x+y;
    41     int p=++nd; sz[p]=sz[x]+sz[y];
    42     ls[p]=merge(ls[x],ls[y]); rs[p]=merge(rs[x],rs[y]);
    43     return p;
    44 }
    45  
    46 void dfs2(int x){
    47     For(i,x) if ((k=to[i])!=fa[x][0]) dfs2(k),rt[x]=merge(rt[x],rt[k]);
    48 }
    49  
    50 int que(int x,int L,int R,int k){
    51     if (L==R) return L;
    52     int mid=(L+R)>>1;
    53     if (k<=sz[ls[x]]) return que(lson,k); else return que(rson,k-sz[ls[x]]);
    54 }
    55  
    56 int main(){
    57     scanf("%d%d",&n,&m);
    58     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    59     dfs(1);
    60     rep(i,1,m) scanf("%d%d",&u,&v),l=lca(u,v),ins(rt[v],1,n,dep[l]),ins(rt[u],1,n,dep[l]);
    61     dfs2(1);
    62     for (scanf("%d",&Q); Q--; ) scanf("%d%d",&v,&k),printf("%d
    ",max(dep[v]-que(rt[v],1,n,k),0));
    63     return 0;
    64 }
    View Code

    6.NOWday2B

    给换上每个位置i一个[1,ai]中的整数,任意两个相邻位置数不相同,求方案数。

    考虑容斥,到位置i时,枚举i与i-1,...,i-k+1都相等,转移为$f_i=sumlimits_{j} f_j imes min(a_{j+1..i}) imes (-1)^{i-j-1}$

    单调队列优化,这里也比较巧妙,具体看代码。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 typedef long long ll;
     5 using namespace std;
     6  
     7 const int N=2e6+7,mod=1e9+7;
     8 ll n,a[N],stk[N][3],f[N],ans,tmp,mn;
     9  
    10 int main(){
    11     scanf("%lld",&n); a[0]=1e9+8;
    12     rep(i,1,n){
    13         scanf("%lld",&a[i]);a[i+n]=a[i];
    14         if(a[i]<a[mn])mn=i;
    15     }
    16     rep(i,1,n) a[i]=a[i+mn-1];
    17     f[0]=n&1?-1:1; int t=1;
    18     stk[1][0]=1e9+8; stk[1][1]=f[0];
    19     rep(i,1,n){
    20         int sum=0;
    21         while(t&&a[i]<stk[t][0])sum=(sum+stk[t--][1])%mod;
    22         f[i]=((f[i]-stk[t][2]-1ll*sum*a[i]%mod)%mod+mod)%mod;
    23         stk[++t][0]=a[i];
    24         stk[t][1]=sum;
    25         stk[t][2]=(1ll*sum*a[i]+stk[t-1][2])%mod;
    26         stk[++t][0]=1e9+8;
    27         stk[t][1]=f[i];
    28         ans=(ans+f[i])%mod;
    29     }
    30     ans=(ans+(n&1?-a[1]:a[1]))%mod;
    31     printf("%lld",ans);
    32     return 0;
    33 }
    View Code

    7.ACday5B

    长度为n的序列A,从中删去恰好k个元素(右边的元素往左边移动),记cnt为新序列中Ai=i的元素个数(即权值与下标相同的元素的个数)。求cnt的最大值。

    f[i]表示以i结尾的序列的最优答案,则有f[i]=max{f[j]+1} (i-j>=a[i]-a[j],a[i]>a[j])。

    考虑按a从小到大的顺序DP,直接树状数组维护即可。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=1000010;
     8 int n,k,ans,f[N],a[N],c[N];
     9 pair<int,int>b[N];
    10 
    11 void add(int x,int d){ x++; for (; x<=n; x+=x&-x) c[x]=max(c[x],d); }
    12 int que(int x){ x++; int res=0; for (; x; x-=x&-x) res=max(res,c[x]); return res; }
    13 
    14 void work(int x){
    15     if (a[x]>x) return;
    16     f[x]=que(x-a[x])+1; add(x-a[x],f[x]);
    17     if (a[x]>=x-k && a[x]<=n-k) ans=max(ans,f[x]);
    18 }
    19 
    20 int main(){
    21     freopen("delete.in","r",stdin);
    22     freopen("delete.out","w",stdout);
    23     scanf("%d%d",&n,&k);
    24     rep(i,1,n) scanf("%d",&a[i]),b[i]=make_pair(a[i],-i);
    25     sort(b+1,b+n+1);
    26     rep(i,1,n) work(-b[i].second);
    27     printf("%d
    ",ans);
    28     return 0;
    29 }
    View Code

    8.ACday5C

    一棵树,选定一个大小为k的连通块,将连通块中所有点编号拿出排序,最大化最长的连续自然数段的长度。

    two pointers枚举所有相邻几个自然数,问题转化为求包含这些点的最小连通块大小。

    这实际上就是求每个点到所有点的LCA的链并,也就是每两个DFS序相邻的点的路径长度和,用经典的DFS序+set维护。

     1 #include<set>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 typedef long long ll;
     7 using namespace std;
     8 typedef set<int>::iterator It;
     9 
    10 const int N=100010;
    11 set<int>S;
    12 int n,k,u,v,sm,cnt,tot,dep[N],dfn[N],b[N],fa[N][18],h[N],nxt[N<<1],to[N<<1];
    13 
    14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    15 
    16 void dfs(int x){
    17     dfn[x]=++tot; b[tot]=x;
    18     rep(i,1,17) fa[x][i]=fa[fa[x][i-1]][i-1];
    19     for (int i=h[x],k; i; i=nxt[i])
    20         if ((k=to[i])!=fa[x][0]) fa[k][0]=x,dep[k]=dep[x]+1,dfs(k);
    21 }
    22 
    23 int lca(int u,int v){
    24     if (dep[u]<dep[v]) swap(u,v);
    25     int t=dep[u]-dep[v];
    26     for (int i=17; ~i; i--) if (t&(1<<i)) u=fa[u][i];
    27     if (u==v) return u;
    28     for (int i=17; ~i; i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    29     return fa[u][0];
    30 }
    31 
    32 int dis(int u,int v){ return dep[u]+dep[v]-2*dep[lca(u,v)]; }
    33 
    34 void ins(int u){
    35     It it2=S.lower_bound(dfn[u]);
    36     if (it2==S.end()) it2=S.begin();
    37     It it1=it2;
    38     if (it1==S.begin()) it1=S.end(),it1--; else it1--;
    39     int x=b[*it1],y=b[*it2];
    40     sm+=dis(x,u)+dis(u,y)-dis(x,y);
    41     S.insert(dfn[u]);
    42 }
    43 
    44 void era(int u){
    45     It it=S.lower_bound(dfn[u]),it1=it;
    46     if (it1==S.begin()) it1=S.end(),--it1; else --it1;
    47     It it2=it; ++it2;
    48     if (it2==S.end()) it2=S.begin();
    49     int x=b[*it1],y=b[*it2];
    50     sm-=dis(x,u)+dis(u,y)-dis(x,y); S.erase(dfn[u]);
    51 }
    52 
    53 int main(){
    54     freopen("power.in","r",stdin);
    55     freopen("power.out","w",stdout);
    56     scanf("%d%d",&n,&k);
    57     rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u);
    58     dfs(1);
    59     int st=1,ans=1; S.insert(dfn[1]);
    60     rep(i,2,n){
    61         ins(i);
    62         if (sm/2+1>k) era(st++);
    63         ans=max(ans,i-st+1);
    64     }
    65     printf("%d
    ",ans);
    66     return 0;
    67 }
    View Code

    9.NOWday3A

    n*m的矩阵,每个格子都有pij的概率为黑,每次矩形边界上的格子和所有与黑格子相邻的格子都会变黑,求每个格子期望在第几次变黑。

    各个事件的独立性会影响概率方程的正确性,所以列的式子尽量不要包含别的概率。

    一个思路是,由于最多会在max(n,m)次内变黑,所以求出每个格子在第i次变黑的概率即可。

    但这样仍然不好求,考虑“每个格子至少i次才能变黑”的概率。

    容易发现,“每个格子至少i次才能变黑”,当且仅当所有离它曼哈顿距离不超过i的格子全是白格子。

    于是问题转化为求以每个格子为中心的菱形的概率积,直接求解即可。

    最后期望就是“至少一次才能变黑的概率”+“至少两次”+“至少三次”+...

    或者根据“至少”得到“恰好”,乘以曼哈顿距离为i+1的点不全为白点的概率即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=210,mod=1e9+7;
     7 int n,m,x,y,v[N][N],ans[N][N],f1[N][N],f2[N][N];
     8 
     9 int ksm(int a,int b){
    10     int res=1;
    11     for (; b; a=1ll*a*a%mod,b>>=1)
    12         if (b & 1) res=1ll*res*a%mod;
    13     return res;
    14 }
    15 
    16 int main(){
    17     freopen("a.in","r",stdin);
    18     freopen("a.out","w",stdout);
    19     scanf("%d%d",&n,&m);
    20     rep(i,1,n) rep(j,1,m)
    21         scanf("%d%d",&x,&y),ans[i][j]=v[i][j]=1ll*x*ksm(y,mod-2)%mod;
    22     rep(j,1,m){
    23         rep(i,1,n){
    24             int s=v[i][j]; f1[i][0]=v[i][j];
    25             rep(k,1,max(n,m)){
    26                 if (j-k<1 || j+k>m) break;
    27                 s=1ll*s*v[i][j-k]%mod*v[i][j+k]%mod;
    28                 f1[i][k]=1ll*f1[i-1][k-1]*s%mod;
    29             }
    30         }
    31         for (int i=n; i; i--){
    32             int s=v[i][j]; f2[i][0]=v[i][j];
    33             rep(k,1,max(n,m)){
    34                 if (j-k<1 || j+k>m) break;
    35                 s=1ll*s*v[i][j-k]%mod*v[i][j+k]%mod;
    36                 f2[i][k]=1ll*f2[i+1][k-1]*s%mod;
    37             }
    38         }
    39         rep(i,1,n) rep(k,1,max(n,m)){
    40             if (j-k<1 || j+k>m) break;
    41             ans[i][j]=(ans[i][j]+1ll*f1[i][k]*f2[i+1][k-1]%mod)%mod;
    42         }
    43     }
    44     rep(i,1,n){ rep(j,1,m) printf("%d ",ans[i][j]); puts(""); }
    45     return 0;
    46 }
    View Code

    10.NOWday3B

    在一张有向无权图(n<=5000)上找到最小的交错环并输出(即环上的边的方向交错),可以有重点但不能有重边。

    考虑拆点,每条边从u出点连向v入点,问题立刻转化为在无向(二分)图上找最小环,暴力从每个点开始BFS即可。

    因为可以证明:如果一个无向图的平均度数至少是8,那么它一定包含一个环。所以bfs时只要搜索最多5000*8条边,一定会找到环并退出。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=10010,M=2000010;
     8 bool vis[N];
     9 int n,m,u,v,q[N],cnt,res[N],Ans[N],h[N],to[M],nxt[M],fa[N];
    10 
    11 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    12 void init(){ cnt=0; memset(h,0,sizeof(h)); }
    13 
    14 int main(){
    15     freopen("b.in","r",stdin);
    16     freopen("b.out","w",stdout);
    17     scanf("%*d");
    18     while (1){
    19         scanf("%d%d",&n,&m); init();
    20         if (n==0) break;
    21         rep(i,1,m) scanf("%d%d",&u,&v),add(u,v+n),add(v+n,u);
    22         int ans=-1;
    23         rep(i,1,n){
    24             memset(vis,0,sizeof(vis));
    25             memset(fa,0,sizeof(fa));
    26             q[1]=i; vis[i]=1;
    27             int tot=0; bool flag=0;
    28             for (int st=0,ed=1; st<ed; ){
    29                 if (flag) break;
    30                 int x=q[++st];
    31                 for (int p=h[x],k; p; p=nxt[p]){
    32                     if (vis[k=to[p]] && k!=fa[x]){
    33                         while (x!=i) res[++tot]=x,x=fa[x];
    34                         res[++tot]=i; reverse(res+1,res+tot+1);
    35                         while (k!=i) res[++tot]=k,k=fa[k];
    36                         flag=1; break;
    37                     }
    38                     if (!vis[k]) vis[k]=1,fa[k]=x,q[++ed]=k;
    39                 }
    40             }
    41             if (tot && (ans==-1 || tot<ans)) ans=tot,swap(Ans,res);
    42         }
    43         printf("%d
    ",ans);
    44         if (ans==-1) continue;
    45         rep(i,1,ans) printf("%d ",(Ans[i]-1)%n+1);
    46         puts("");
    47     }
    48     return 0;
    49 }
    View Code

    11.NOWday3C

    有一堆石子,先手可取任意数量的石子但是无法直接全部取走,此后每个人可取前一个人取走的k倍以内任意数量的石子(不能不取),取走最后一个石子的赢,问先手是否必胜。

    部分分:容易得到kn的DP算法,并发现k=2时所有必败态都在fibonacci数点上。

    结论:若先手在n=n0时输,那么找到[n0/k,n0)中最小的m0使先手输,则先手在n=n0+m0时同样必败(而在(n0,n0+m0)中均必胜)。

    由此可以直接找到所有必败点。

    证明:若n在(n0,n0+m0)中,则先手将石子数变为n0即可。n=n0+m0时,先手无法取m0(太大),则后手可以取m0到必胜态。得证。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 ll m,n,i,j,T,nw[10000010];
     9 
    10 int main(){
    11     freopen("c.in","r",stdin);
    12     freopen("c.out","w",stdout);
    13     for (scanf("%lld",&T); T--; ){
    14         scanf("%lld%lld",&m,&n);
    15         if(n<=m+1){ puts("DOG"); continue; }
    16         for (i=1; i<=m+1; ++i) nw[i]=i;
    17         j=1;
    18         while (nw[i-1]<n){
    19             while ((nw[i-1]-1)/nw[j]>=m) ++j;
    20             nw[i]=nw[i-1]+nw[j]; ++i;
    21         }
    22         puts(nw[i-1]==n?"DOG":"GOD");
    23     }
    24     return 0;
    25 }
    View Code

    12.ACday6B

    四个梯子,n层每层只有一个梯子在这层有木块,问有多少种方案,满足存在一个梯子,任意两个有木块的层之间距离不超过d(第一块要小于等于d,最后一块要大于等于n-d)。(n<=1000,d<=30)

    容易想到f[i][x][y][z][w]的DP,若一个梯子存在间隔超过d的层则直接记为d层,故状态数是nd^4的。

    考虑去掉一维,对于当前正在考虑的这层所放的梯子,只需要管它是死是活即可。状态变为f[i][0/1][x][y][z],DP之间的转移要考虑清楚。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=35,mod=1e9+9;
     8 int n,h,f[2][2][N][N][N],u,ans;
     9 
    10 int cal(int x){ return min(x+1,h); }
    11 void inc(int &x,int y){ x+=y; if (x>=mod) x-=mod; }
    12 
    13 int main(){
    14     freopen("ladder.in","r",stdin);
    15     freopen("ladder.out","w",stdout);
    16     scanf("%d%d",&n,&h); f[u=0][1][1][1][1]=1;
    17     rep(p,2,n){
    18         u^=1; memset(f[u],0,sizeof(f[u]));
    19         rep(i,0,h) rep(j,0,h) rep(k,0,h){
    20             int t=f[u^1][0][i][j][k];
    21             inc(f[u][i<h][h][cal(j)][cal(k)],t);
    22             inc(f[u][j<h][cal(i)][h][cal(k)],t);
    23             inc(f[u][k<h][cal(i)][cal(j)][h],t);
    24             inc(f[u][0][cal(i)][cal(j)][cal(k)],t);
    25             t=f[u^1][1][i][j][k];
    26             inc(f[u][i<h][1][cal(j)][cal(k)],t);
    27             inc(f[u][j<h][cal(i)][1][cal(k)],t);
    28             inc(f[u][k<h][cal(i)][cal(j)][1],t);
    29             inc(f[u][1][cal(i)][cal(j)][cal(k)],t);
    30         }
    31     }
    32     rep(i,0,h) rep(j,0,h) rep(k,0,h)
    33         inc(ans,f[u][0][i][j][k]),inc(ans,f[u][1][i][j][k]);
    34     inc(ans,mod-f[u][0][h][h][h]);
    35     printf("%lld
    ",4ll*ans%mod);
    36     return 0;
    37 }
    View Code

    13.NOWday5A

     求x在[0,n],y在[0,m]且(x^y)%m=0的(x,y)个数,n,m<=1e18。

    见代码。

     1 ll solve(ll a,ll b){
     2     ll ans=0; a++; b++;
     3     rep(i,0,60) if (a&(1ll<<i))
     4         rep(j,0,60) if (b&(1ll<<j)){
     5             int k=max(i,j);
     6             ll l=((a^(1ll<<i))^(b^(1ll<<j)))&(~((1ll<<k)-1)),r=l+(1ll<<k)-1;
     7             ans=(ans+(r/m-l/m+(l%m==0))%mod*((1ll<<min(i,j))%mod))%mod;
     8         }
     9     return ans;
    10 }
    View Code

    14.NOWday5C

    求有多少对01串S,T,满足:

    1. S有a个0,b个1

    2. T有c个0,d个1

    3. T是S的子序列。

    a,b,c,d<=2000

    当T确定时,考虑往T上加a-c个0和b-d个1得到S。为了避免重复,规定T一定要是S的第一个长这样的子序列。

    于是每个0就只能加在T中某个1的前面,或T的末尾。1同理。

    枚举有多少个0和1不加在末尾,组合数求解,最后乘上C(c+d,c)即可。特判c=0或d=0。

    rep(i,0,b) rep(j,0,a) ans+=C(c+i-1,c-1)*C(d+j-1,d-1)*C(a-c+b-d-i-j,b-d-i);

    15.WHday1

    5个大小为200的集合,要求从5个集合中各选一个使和为0,求方案数。

    分成2+2+1的形式,枚举1的那200个数,将另外两个排序双指针扫一下即可。

    16.WHday2

    n棵树,每棵树有a[i]个桃子,掉落的速度是每天d[i]个。接下来k天,每天可以将一棵树上的桃子摘光,求最大摘桃数。(n,k<=1000)
    显然最优解中是按d从大到小摘的,那么我们将所有数按d排序后直接DP即可。

    17.WHday3T1

    n个点,每个点有两个值s和l,当i<j且|si-sj|<=li+lj时,从i到j连一条长度为(j-i)^2的边,求1到n的最短路。
    乱搞做法:每一次从i到j显然是j-i越小越好,那么每次只考虑从i跳到i+1,i+2,...,i+12,可得90分。
    正解:显然DP,发现每个点可以抽象成一个[si-li,si+li]的区间,两区间有交即可连边。于是用set维护一个区间集合。容易证明,若两个区间有交,则交的部分一定取编号较大的一个,于是set中存的区间都是互不相交的。每次加入新的区间时,先找到set中与它相交的区间进行转移,再用这个区间覆盖别的区间,复杂度O(nlogn)。

    18.WHday3T2

    支持两种操作:区间覆盖成某种颜色,区间查询共有多少种不同的颜色。颜色数<=30
    如果是单点修改,就是经典原题,记录每个位置的lst(即上个和它颜色相同的位置),则询问就是求lst<l的位置的个数。
    但这个题不要陷入惯性思维,由颜色数入手,使用线段树,用二进制记录每个区间有哪些颜色,支持区间覆盖和或运算即可。

    19.WHday6T1

    n个数,每次询问有多少种子集选法,使子集和为m倍数,相等数算不同选法。n<=1e5,Q<=30,m<=100。

    O(nmQ)的不难想到,70分。发现每个数x和x%m是完全等价的,于是考虑将复杂度优化成O(Q(nm+m^3))。

    首先用桶记录0~m-1每个数出现的次数,然后f[i][j]表示前i个数凑成j的方案数。

    显然有f[i][j]=f[i-1][j-k*a[i]]*C(n,k),状态数只有O(n^2),考虑去掉k对复杂度的影响。

    预处理p[i][j]记录数i对凑成j的方案数C的影响(也就是C之和),转移时直接枚举f[i-1][l]*p[i][i-l]即可。

    20.WHday6T2

    平面上n个点,用K个边长为L的正方形覆盖所有点,最小化L。n<=1e5,K<=3。

    K=1直接求解。

    K=2找到覆盖所有点的最小矩形,则两个正方形一定分别在矩形的两个对角上,答案为max{min(max(xi-x0,yi-y0),max(x1-xi,y1-yi))}。

    K=3肯定有至少一个正方形在矩形的一个角上,讨论在哪个角上并二分这个正方形的边长,问题转化为K=2的情况。

    21.WHday6T3

    在一张有向图上随便走(步数可无限),第i步走到的点x的贡献为x*r^i,求能走出的最大收益,保留一位小数。n<=100,0<r<0.999999。

    先将有限情况直接算出,步数不可能超过n步。

    无限情况显然不可能精确算出,但如果能考虑往后走2^30步的最大收益,精度上就几乎没有误差了。

    套路:f[i][j][p]表示从i走2^p步到j的最大收益,转移枚举走2^(p-1)步时到的点k,则f[i][j][p]=f[i][k][p-1]+f[k][j][p-1]*(w^(2^(p-1)))。

    22.NOWday5T1

    一张有向图上,每个点有一个字符,求从每个点出发的字典序最小的最长路。

    方法一:难点主要在于比较两条路径的字典序,而比较只会发生在离终点距离相等的点之间,所以只要在拓扑时用优先队列,保证同层点之间的大小关系即可。

     1 #include<queue>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 using namespace std;
     7  
     8 const int N=1000010,mod=998244353;
     9 int n,m,u,v,w,cnt,tot,ind[N],ans[N],rk[N],fr[N],pre[N],dis[N],h[N],to[N],nxt[N],val[N];
    10 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
    11  
    12 struct P{ int x,dis,pre,rk; };
    13 bool operator <(const P &a,const P &b){
    14     return (a.dis==b.dis) ? ((a.pre==b.pre) ? a.rk>b.rk : a.pre>b.pre) : a.dis>b.dis;
    15 }
    16 priority_queue<P>Q;
    17  
    18 void Top(){
    19     rep(i,1,n) if (!ind[i]) Q.push((P){i,0,0,0}),ans[i]=0;
    20     while (!Q.empty()){
    21         int x=Q.top().x; Q.pop(); rk[x]=++tot;
    22         if (ans[x]==-1) ans[x]=29ll*(ans[fr[x]]+pre[x])%mod;
    23         for (int i=h[x]; i; i=nxt[i]){
    24             int k=to[i];
    25             if ((dis[k]<dis[x]+1) || ((dis[k]==dis[x]+1) && ((val[i]<pre[k]) || (val[i]==pre[k] && rk[fr[k]]>rk[x]))))
    26                 dis[k]=dis[x]+1,pre[k]=val[i],fr[k]=x;
    27             if (!--ind[k]) Q.push((P){k,dis[k],pre[k],rk[fr[k]]});
    28         }
    29     }
    30 }
    31  
    32 int main(){
    33     scanf("%d%d",&n,&m);
    34     rep(i,1,m) scanf("%d%d%d",&u,&v,&w),add(v,u,w),ind[u]++;
    35     memset(ans,-1,sizeof(ans)); Top();
    36     rep(i,1,n) if (ans[i]==-1) puts("Infinity"); else printf("%d
    ",ans[i]);
    37     return 0;
    38 }
    View Code

    方法二:hash+倍增。找出第一个不同的位置比较。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5  
     6 typedef long long ll;
     7  
     8 const int mod=998244353,P1=31,P2=19260817;
     9 const int N=1000010;
    10 int n,m,u,v,w,cnt,ans[N],dis[N],ind[N],pw[N],q[N],f[N][21],g[N][21],h[N],to[N],val[N],nxt[N];
    11 void add(int u,int v,int w){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
    12  
    13 bool Cmp(int x,int y){
    14     for (int i=20; ~i; i--)
    15         if (f[x][i] && f[y][i] && g[x][i]==g[y][i]) x=f[x][i],y=f[y][i];
    16     return g[x][0]>g[y][0];
    17 }
    18  
    19 int main(){
    20     scanf("%d%d",&n,&m);
    21     rep(i,1,m) scanf("%d%d%d",&u,&v,&w),add(v,u,w),ind[u]++;
    22     pw[0]=P1; rep(i,1,20) pw[i]=1ll*pw[i-1]*pw[i-1]%P2;
    23     int st=0,ed=0;
    24     rep(i,1,n) if (!ind[i]) q[++ed]=i;
    25     while (st<ed){
    26         int x=q[++st];
    27         rep(i,1,20) f[x][i]=f[f[x][i-1]][i-1],g[x][i]=(1ll*g[x][i-1]*pw[i-1]%mod+g[f[x][i-1]][i-1])%mod;
    28         for (int i=h[x]; i; i=nxt[i]){
    29             int k=to[i];
    30             if (dis[x]+1>dis[k] || (dis[x]+1==dis[k] && (g[k][0]>val[i] || (g[k][0]==val[i] && Cmp(f[k][0],x)))))
    31                 g[k][0]=val[i],f[k][0]=x,ans[k]=29ll*(ans[x]+val[i])%mod,dis[k]=dis[x]+1;
    32             if (!--ind[k]) q[++ed]=k;
    33         }
    34     }
    35     rep(i,1,n) if (ind[i]) puts("Infinity"); else printf("%d
    ",ans[i]);
    36     return 0;
    37 }
    View Code

    23.求a+b<=n且a+b|ab的数对(a,b)数量,n<=1e12。

    设d=gcd(a,b),a'=a/d,b'=b/d,则有(a'+b')d|a'b'd^2。

    因为若a与b互质,则a+b与ab互质,故有a'+b'|d。

    由a'+b'<=d且(a'+b')d<=n,得到a'+b'<=sqrt(n)。

    枚举k=a'+b',则对于每个k有n/k^2个d(a'+b'|d且d<=n/(a'+b')),和phi(k)个a。

    24.给定数列a,多次询问(l,r,k),回答a[l~r]中模k最大的数。n,k<=1e5。

    发现对于每个k,[ak,(a+1)k)之间的最大值一定是这些数%k的最大值,这样的区间一共klogk个。

    分块,预处理ans[i][j]表示第i块模j的最大值。块的大小设为sqrt(klogk)。

    考虑如何计算ans,对每块开个桶记录不大于某个数的最大的数,然后klogk枚举所有区间更新。

    25.(1)[ACday9A][BZOJ4773]一张有向带权图,找边数最少的负环,输出边数。(n<=300)

    首先发现,floyd可以看作类似矩阵乘法的操作,而矩阵乘法是可以快速幂加速的,于是这个题的思路就比较清晰了。

    f[l][i][j]表示从i走2^l以内步到j,能走出的最小边权和,通过枚举中间点转移,然后用类似倍增LCA的方法求出答案。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=310,inf=1e9;
     7 int n,m,ans,u,v,w,f[10][N][N],now[N][N],tmp[N][N];
     8 
     9 void mul(int a[N][N],int b[N][N],int c[N][N]){
    10     rep(i,1,n) rep(j,1,n) c[i][j]=inf;
    11     rep(k,1,n) rep(i,1,n) rep(j,1,n)
    12         if (a[i][k]!=inf && b[k][j]!=inf) c[i][j]=min(c[i][j],a[i][k]+b[k][j]);
    13 }
    14 
    15 int main(){
    16     freopen("bzoj4773.in","r",stdin);
    17     freopen("bzoj4773.out","w",stdout);
    18     scanf("%d%d",&n,&m);
    19     rep(k,0,9) rep(i,1,n) rep(j,1,n) f[k][i][j]=inf;
    20     rep(i,1,n) rep(j,1,n) now[i][j]=inf;
    21     rep(i,1,n) f[0][i][i]=now[i][i]=0;
    22     rep(i,1,m) scanf("%d%d%d",&u,&v,&w),f[0][u][v]=w;
    23     rep(i,1,9) mul(f[i-1],f[i-1],f[i]);
    24     for (int i=9; ~i; i--){
    25         mul(now,f[i],tmp); bool flag=0;
    26         rep(j,1,n) if (tmp[j][j]<0) flag=1;
    27         if (!flag){
    28             ans|=1<<i;
    29             rep(j,1,n) rep(k,1,n) now[j][k]=tmp[j][k];
    30         }
    31     }
    32     if (ans>n) puts("0"); else printf("%d
    ",ans+1);
    33     return 0;
    34 }
    View Code

    (2)[NOW7day7C]一张有向图无权图,每次询问ui到vi是否存在长度为li的路径。(n<=100,l<=1e9)

    类似的想法,f[l][i][j]表示i走2^l以内步能否到达j,每次将li二进制拆分,更新能到达的状态集合,使用bitset优化O(n^3logn/64)。

     1 #include<bitset>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<iostream>
     6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     7 #define For(i,x) for (int i=h[x]; i; i=nxt[i])
     8 typedef long long ll;
     9 using namespace std;
    10 
    11 const int N=110;
    12 int n,m,u,v,Q,l;
    13 bitset<N>f[31][N],to[2];
    14 
    15 int main(){
    16     freopen("c.in","r",stdin);
    17     freopen("c.out","w",stdout);
    18     scanf("%d%d",&n,&m);
    19     rep(i,1,m) scanf("%d%d",&u,&v),f[0][u][v]=1;
    20     rep(j,1,30) rep(i,1,n) rep(k,1,n) if (f[j-1][i][k]) f[j][i]|=f[j-1][k];
    21     for (scanf("%d",&Q); Q--; ){
    22         scanf("%d%d%d",&l,&u,&v);
    23         int p=1,q=0;
    24         to[0].reset(); to[1].reset(); to[0][u]=1;
    25         rep(j,0,30) if (l&(1<<j)){
    26             p^=1; q^=1; to[q].reset();
    27             rep(i,1,n) if (to[p][i]) to[q]|=f[j][i];
    28         }
    29         puts((to[q][v])?"YES":"NO");
    30     }
    31     return 0;
    32 }
    View Code

    26.经典问题:一张无向带权连通图,每次询问ui到vi是否存在一条路径(可以走环)异或和为wi。(n<=1e5)

    先求出图的一棵生成树,非树边的权值全部由val变为val^s[u][lca]^s[v][lca],其中s[i][j]为i到j的路径异或和。

    对非树边建线性基,每次将询问扔进线性基查询即可。

    27.NOWday8C

    双人博弈,轮流操作,每次从数列两端共选k个数删去(k|n-1),A要使最后留下的数最大,B要使最小。A先手,求最终剩下的数。线性。

    实际上要求游戏的纳什均衡点。先考虑最后一步A取的情况。

    考虑到若对A来说均衡点在最中间k个数中,则A一定能通过模仿B的操作(即B首选了x个,尾y个,则A反之)从而保证最后未删的点就是这个数。而若不在最中间的k个数中,B一定能通过模仿A从而删掉这个数打破平衡。故最终答案只要在最中间的k个数中取max即可。

    若最后一步B取,则B也同理会在最中间的k个数中选出最小的,则A的最后一步决策一定是在最中间的连续2k个数中找最小值最大的一个长度为k的区间。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=1000010;
     7 int T,a[N],n,k,P,q[N];
     8 char s[N];
     9 
    10 int main(){
    11     for (scanf("%d",&T); T--; ){
    12         scanf("%s",s); scanf("%d%d",&n,&k);
    13         if (s[2]=='w') rep(i,1,n) scanf("%d",&a[i]);
    14         else{
    15             scanf("%d%d",&a[1],&P);
    16             rep(i,2,n) a[i]=(2333ll*a[i-1]+6666)%P;
    17         }
    18         if ((n-1)/k&1){
    19             int ans=0,mid1=(n-k+1)/2, mid2=k+(n-k+1)/2;
    20             rep(i,mid1,mid2) ans=max(ans,a[i]);
    21             printf("%d
    ", ans);
    22         }
    23         else{
    24             int ans=0,mid1=(n-2*k+1)/2,mid2=2*k+(n-2*k+1)/2,l=1,r=0;
    25             rep(i,mid1,mid2){
    26                 while (l<=r && q[l]<i-k) l++;
    27                 while (l<=r && a[q[r]]>a[i]) r--;
    28                 q[++r]=i;
    29                 if (i>=mid1+k) ans=max(ans,a[q[l]]);
    30             }
    31             printf("%d
    ", ans);
    32         }
    33     }
    34     return 0;
    35 }
    View Code
  • 相关阅读:
    [搜片神器]单服务器程序+数据库流程优化记录
    [搜片神器]直接从DHT网络下载BT种子的方法
    [搜片神器]winform程序自己如何更新自己的方法代码
    实时排行榜的后台数据功能实现
    我的Java之旅 第八课 Servlet 进阶API、过滤器与监听器
    我的Java之旅 第七课 JAVA WEB 会话管理
    我的Java之旅 第六课 JAVA WEB 请求与响应
    我的Java之旅 第五课 JAVA 语言语法 集合
    我的Java之旅 第四课 JAVA 语言语法 基础
    我的Java之旅 第三课 从Applet到JSP
  • 原文地址:https://www.cnblogs.com/HocRiser/p/9672336.html
Copyright © 2011-2022 走看看