这几个是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 2100000000
using 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 400100
using 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 1000000007
using 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 原题(...)