WXH♂Round

来源:互联网 发布:路由器显示网络不可用 编辑:程序博客网 时间:2024/05/22 15:14

这几个是YJQ(搬)的题,补补题解好了

T1:WXH要表演,每天可以倒立表演或正常表演,倒立表演有Ai的收益,正常有Bi的收益,要求每连续K天必须有P个倒立,Q个正常

网络流,相当于必须[Q,K-P]个正常表演,设为[l,r],先假设都是倒立表演

建图如下:每一天建一个点,先给前K天r个,表示只能改r个.

i天向i+k天连边,花费Bi-Ai,流量1,表示这一天可以换成正常,但要到i+k天才能再改。

i天向i+1天连边,流量r-l,表示至少要走l个为正常表演

#include<bits/stdc++.h>#define maxn 300#define maxm 100000#define inf 2100000000using namespace std;struct edge{int r,nxt,w,cost;}e[maxm];int S,T,n,a[maxn],b[maxn],vis[maxn],q[600],l,r,K,dis[maxn],P,Q,head[maxn],esz=1,ans;void addedge(int u,int v,int w,int cost){e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;e[esz].w=w;e[esz].cost=cost;e[++esz].r=u;e[esz].nxt=head[v];head[v]=esz;e[esz].w=0;e[esz].cost=-cost;}int spfa(){for(int i=S;i<=T;++i)dis[i]=inf,vis[i]=0;l=r=0,q[r++]=S,dis[S]=0;while(l^r){int u=q[l++];vis[u]=0;l&=511;for(int t=head[u];t;t=e[t].nxt)if(e[t].w&&dis[e[t].r]>dis[u]+e[t].cost)dis[e[t].r]=dis[u]+e[t].cost,(vis[e[t].r]?0:q[r++]=e[t].r,r&=511,vis[e[t].r]=1);}return dis[T]!=inf;}int find(int u,int flow){if(u==T)return flow;vis[u]=1;int used=0,a=0;for(int t=head[u];t&&used<flow;t=e[t].nxt)if(e[t].w&&dis[e[t].r]==dis[u]+e[t].cost&&!vis[e[t].r])a=find(e[t].r,min(flow-used,e[t].w)),e[t].w-=a,e[t^1].w+=a,ans+=e[t].cost*a,used+=a;return used;}int main(){scanf("%d%d%d%d",&n,&K,&r,&l),r=K-r;for(int i=1;i<=n;++i)scanf("%d%d",&a[i],&b[i]),ans-=a[i];S=0,T=n+2;addedge(S,n+1,r,0);for(int i=1;i<=K;++i)addedge(n+1,i,inf,0);for(int i=1;i<=n;++i){addedge(i,i==n?T:i+1,r-l,0);addedge(i,i+K>n?T:i+K,1,a[i]-b[i]);}while(spfa())find(S,inf);printf("%d",-ans);}
T2:3w暴力过了

T3:

容易发现,如果从(1,...1)到(x1,..,xn)的路径数为奇数,则为白点。

因为(1,...1)是白点路径数为奇数,K个前驱中有奇数个白点这个点才是白点,则这个白点路径数也为奇数。

把L[i]--,R[i]--.

考虑2维,则C(x,x+y)%2==1就是白点。

考虑lucas.若x,y二进制下有一位都为1,则产生进位,这样必然存在一个x的二进制位比x+y大,即C(x,x+y)为偶数.

故x,y每个二进制位1的个数<=1

对于n维,路径数为C(x1,x1+...+xn)*C(x2,x2+...xn)*...*C(xn-1,xn-1+xn),可以发现结论依然成立。


考虑数位DP,用3^k来表示每一维是否顶上界,0代表同时顶L,R或同时不顶L,R;1代表顶L;2代表顶R

转移推一推即可

#include<bits/stdc++.h>#define mod 998244353#define get(x,y) (!!((x)&(1ll<<(y))))using namespace std;long long L[20],R[20];int n,dp[2][20000],flag[20],pw[20]={1},a[20];int main(){scanf("%d",&n);for(int i=1;i<20;++i)pw[i]=pw[i-1]*3;for(int i=0;i<n;++i)scanf("%lld%lld",&L[i],&R[i]),L[i]--,R[i]--;int np=0,p=1;dp[np][0]=1;for(int i=59;i>=0;--i,swap(p,np)){int _pos=-1;for(int k=0;k<n;++k)if(get(L[k],i)==get(R[k],i)&&get(L[k],i)==1&&!flag[k]){if(_pos>=0)return puts("0"),0;else _pos=k;}for(int j=0;j<pw[n];++j)if(dp[np][j]){//printf("<%d,%d,%d>\n",i,j,dp[np][j]);int pos=_pos,nj=j;for(int k=0;k<n;++k)a[k]=j/pw[k]%3;for(int k=0;k<n;++k)if(flag[k]&&a[k]==1&&get(L[k],i)==1){if(pos>=0)goto nxt; else pos=k;}for(int k=0;k<n;++k)if(k!=pos){if(flag[k]){if(a[k]==2&&get(R[k],i)==1)nj-=2*pw[k];} else if(get(L[k],i)!=get(R[k],i))nj+=pw[k];}dp[p][nj]=(dp[p][nj]+dp[np][j])%mod;if(pos==-1)for(int k=0;k<n;++k){int _nj=nj;if(flag[k]){if(a[k]==1)_nj-=pw[k];else if(a[k]==2){if(get(R[k],i)==1)_nj+=2*pw[k];else continue;}} else if(get(L[k],i)!=get(R[k],i))_nj+=pw[k];else continue;//printf("[%d,%d]",k,get(L[k],i));for(int l=0;l<n;++l)printf("%d[%d,%d] ",a[l],get(L[l],i),get(R[l],i));printf("->");//for(int l=0;l<n;++l)printf("%d ",_nj/pw[l]%3);puts("");dp[p][_nj]=(dp[p][_nj]+dp[np][j])%mod;}nxt:;dp[np][j]=0;}for(int k=0;k<n;++k)if(get(L[k],i)!=get(R[k],i))flag[k]=1;}int ans=0;for(int i=0;i<pw[n];++i)ans=(ans+dp[np][i])%mod;printf("%d",ans);}

WXH♂Round #2

T1:有N个WXH,有Vi,Pi,且(Vi,Pi互不相同)YJQ想要硬点一些WXH,给他们标标记.相遇时标记会传递.问有多少种方法使得最后所有的WXH都有标记

可以发现每个人影响的都是一个速度区间(要是Vi可以相同,也是一个区间)

相当于选一些区间覆盖n个点的方案数

令dp[i]表示[1,i]覆盖的方案数

当我们选一个区间[L,R]时,原先的dp[R...n]会*2,因为我们选不选这个区间对覆盖没有影响.再用dp[L-1...R-1]更新dp[R]

模数抄成666623333...智商-1.jpg

#include<bits/stdc++.h>#define mod 66662333#define inf 1000000007#define maxn 400100using namespace std;struct data{int p,v,s;data(){}data(int p,int v,int s):p(p),v(v),s(s){}}A[maxn];struct _query{int l,r;int operator<(const _query q)const{return l==q.l?r>q.r:l<q.l;}}q[maxn];int add[maxn<<2],s[maxn<<2],n,mx[maxn],mn[maxn],lsh[maxn],tp;int c1(data a,data b){return a.p<b.p;}void upd(int o){s[o]=(s[o<<1]+s[o<<1|1])%mod;}void pushdown(int o){if(add[o]^1){add[o<<1]=1ll*add[o<<1]*add[o]%mod,add[o<<1|1]=1ll*add[o<<1|1]*add[o]%mod,s[o<<1]=1ll*s[o<<1]*add[o]%mod,s[o<<1|1]=1ll*s[o<<1|1]*add[o]%mod,add[o]=1;}}void cheng(int o,int l,int r,int ql,int qr){if(ql<=l&&r<=qr){add[o]=(add[o]<<1)%mod,s[o]=(s[o]<<1)%mod;return ;}int mid=l+r>>1;pushdown(o);if(ql<=mid)cheng(o<<1,l,mid,ql,qr);if(qr>mid)cheng(o<<1|1,mid+1,r,ql,qr);upd(o);}void modify(int o,int l,int r,int k,int tg){if(l==r){s[o]=(s[o]+tg)%mod;return ;}int mid=l+r>>1;pushdown(o);if(k<=mid)modify(o<<1,l,mid,k,tg);else modify(o<<1|1,mid+1,r,k,tg);upd(o);}int query(int o,int l,int r,int ql,int qr){if(ql<=l&&r<=qr)return s[o];int mid=l+r>>1,ans=0;pushdown(o);if(ql<=mid)ans+=query(o<<1,l,mid,ql,qr);if(qr>mid)ans+=query(o<<1|1,mid+1,r,ql,qr);return ans%mod;}void build(int o,int l,int r){add[o]=1;if(l==r){s[o]=(l==0?1:0);return ;}int mid=l+r>>1;build(o<<1,l,mid);build(o<<1|1,mid+1,r);upd(o);}int main(){scanf("%d",&n);for(int i=1;i<=n;++i)scanf("%d%d",&A[i].p,&A[i].v),lsh[++tp]=A[i].v;sort(A+1,A+n+1,c1),sort(lsh+1,lsh+tp+1);for(int i=1;i<=n;++i)A[i].v=lower_bound(lsh+1,lsh+tp+1,A[i].v)-lsh;mx[0]=0,mn[n+1]=inf;for(int i=1;i<=n;++i)mx[i]=(mx[i-1]<A[i].v?A[i].v:mx[i-1]);for(int i=n;i>=1;--i)mn[i]=(mn[i+1]>A[i].v?A[i].v:mn[i+1]);for(int i=1;i<=n;++i)q[i]=_query{min(A[i].v,mn[i+1]),max(A[i].v,mx[i-1])};sort(q+1,q+n+1),build(1,0,n);for(int i=1;i<=n;++i){cheng(1,0,n,q[i].r,n);modify(1,0,n,q[i].r,query(1,0,n,q[i].l-1,q[i].r-1));}printf("%d",query(1,0,n,n,n));}

T2:

这题题意好绕。。。

最暴力的暴力大概是这样的:维护一个p=0

每次增加一个字符时,枚举左端点l,然后对于子串[l,r]暴力求fail,然后暴力跳fail且p++,然后ans+=p;

考虑后缀自动机,当增加一个字符时,对于每个right集合包含r的子串,p+=|right集合|

解释:跳fail的过程一定能将所有right集合包含r的子串计算到

代码大概是这样:for(;j;j=fail[j])p+=size[j]*(len[j]-len[fail[j]]),size[j]++;ans+=p;

这样就简单了,只需要换成树链剖分维护就行了

#include<bits/stdc++.h>#define maxn 200100#define mod 1000000007using namespace std;struct edge{int r,nxt;}e[maxn<<1];int trie[maxn][26],n,fail[maxn],len[maxn],ptr=1,rt=1,lst=1;int A[maxn],head[maxn],esz,fa[maxn],top[maxn],son[maxn],id[maxn],fid[maxn],tim;int s[maxn<<2],addv[maxn<<2],sum[maxn<<2],ans,size[maxn],ans2;char c[maxn];void addedge(int u,int v){e[++esz].r=v;e[esz].nxt=head[u];head[u]=esz;}int dfs1(int u){int s,mxs=0,sz=1;for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=fa[u]){fa[e[t].r]=u,s=dfs1(e[t].r),sz+=s;if(mxs<s)mxs=s,son[u]=e[t].r;}return sz;}void dfs2(int u,int tp){id[u]=++tim,fid[tim]=u,top[u]=tp;if(son[u])dfs2(son[u],tp);for(int t=head[u];t;t=e[t].nxt)if(e[t].r!=fa[u]&&e[t].r!=son[u])dfs2(e[t].r,e[t].r);}void build(int o,int l,int r){if(l==r){s[o]=len[fid[l]]-len[fail[fid[l]]];return ;}int mid=l+r>>1;build(o<<1,l,mid),build(o<<1|1,mid+1,r);s[o]=(s[o<<1]+s[o<<1|1])%mod;}void modify(int o,int l,int r,int ql,int qr,int tg){if(ql<=l&&r<=qr){addv[o]+=tg,sum[o]=(sum[o]+1ll*s[o]*tg)%mod;return ;}int mid=l+r>>1;if(addv[o])addv[o<<1]+=addv[o],addv[o<<1|1]+=addv[o],sum[o<<1]=(sum[o<<1]+1ll*addv[o]*s[o<<1])%mod,sum[o<<1|1]=(sum[o<<1|1]+1ll*addv[o]*s[o<<1|1])%mod,addv[o]=0;if(ql<=mid)modify(o<<1,l,mid,ql,qr,tg);if(qr>mid)modify(o<<1|1,mid+1,r,ql,qr,tg);sum[o]=(sum[o<<1]+sum[o<<1|1])%mod;}int query(int o,int l,int r,int ql,int qr){if(ql<=l&&r<=qr)return sum[o];int mid=l+r>>1;if(addv[o])addv[o<<1]+=addv[o],addv[o<<1|1]+=addv[o],sum[o<<1]=(sum[o<<1]+1ll*addv[o]*s[o<<1])%mod,sum[o<<1|1]=(sum[o<<1|1]+1ll*addv[o]*s[o<<1|1])%mod,addv[o]=0;int ans=0;if(ql<=mid)ans+=query(o<<1,l,mid,ql,qr);if(qr>mid)ans+=query(o<<1|1,mid+1,r,ql,qr);return ans%mod;}void append(int c){int cur=++ptr,p=lst;len[cur]=len[lst]+1;for(;p&&!trie[p][c];p=fail[p])trie[p][c]=cur;if(!p){fail[cur]=1;} else {int q=trie[p][c];if(len[q]==len[p]+1){fail[cur]=q;} else {int cl=++ptr;fail[cl]=fail[q];len[cl]=len[p]+1;memcpy(trie[cl],trie[q],sizeof(trie[q]));for(;p&&trie[p][c]==q;p=fail[p])trie[p][c]=cl;fail[cur]=fail[q]=cl;}}lst=cur;}void calc(int u){while(u){ans=(ans+query(1,1,tim,id[top[u]],id[u]))%mod;modify(1,1,tim,id[top[u]],id[u],1),u=fa[top[u]];}//for(;u;u=fail[u])//ans=(ans+1ll*size[u]*(len[u]-len[fail[u]]))%mod,size[u]++;}int main(){scanf("%d%s",&n,c+1);for(int i=1;i<=n;++i)append(c[i]-'a'),A[i]=lst;for(int i=2;i<=ptr;++i)addedge(fail[i],i);//,printf("{%d}",fail[i]);dfs1(1),dfs2(1,1),build(1,1,tim);//for(int i=1;i<=tim;++i)printf("[%d,%d]",top[i],id[i]);for(int i=1;i<=n;++i)calc(A[i]),printf("%d\n",(ans2+=ans)%=mod);}
T3:TopCoder 原题(...)


原创粉丝点击