arc100_d
题目叙述
求所有的长度为 \(n\) 的序列,每个位置的取值是 \([1,k]\) 内的整数,并且不存在连续 \(k\) 个数满足他们互不相同。求所有这样的序列,\(A_1\sim A_M\) 这个序列出现了多少次。
题解
“存在连续 \(k\) 个互不相同的”转化为“不存在连续 \(k\) 个互不相同的”。
只要总数去掉 \(A\) 在不存在连续 \(k\) 个互不相同的序列中出现的次数即可。
可以发现,如果 \(A\) 本身就有长度为 \(k\) 的连续段满足互不相同,这是容易计算的。
那么,剩下两种情况:
- \(A\) 中存在相同的数
- \(A\) 中不存在相同的数
先考虑第二种。
事实上,第二种情况的答案与 \(A\) 序列具体是什么并没有关系。因为是互不相同的情况。
所以其实就相当于统计所有序列中相邻 \(M\) 个互不相同的连续段的数量。
设 \(g_{i,j}\) 表示前 \(i\) 个,最后 \(j\) 个互不相同的方案数。
考虑讨论第 \(i-1\) 位往前一共有多少个互不相同的数。至少有 \(j-1\) 个互不相同的数。
- 如果恰好 \(j-1\) 个互不相同的。那么从 \(g_{i-1,j-1}\) 转移。当前这一位有 \(k-(j-1)\) 中填法。
- 否则 \(\ge j\) 个互不相同的数。那么一定第 \(i\) 个数和前面那个相同。当前这一位只有一种填法。
在此同时我们还需要计算前 \(i\) 个,最后 \(j\) 个互不相同的所有序列中连续 \(M\) 个互不相同的连续段数量总和为 \(f_{i,j}\) 。
最后再除掉 \(k^{\underline{M}}\) 就可以了。
对于第二种情况,考虑直接找到最长的连续不同的前缀和后缀,然后拼起来即可。
总结
- 识别特征不仅需要直觉,还需要关键字。要对“存在”敏感。
- 有的时候计算单个不好计算,可以补上一些相同的。就像arc100_d的做法,统计所有序列中 \(M\) 个互不相同的子串数量。
代码
#include <cstdio>
#include <iostream>
#include <queue>
#include <set>
#define macro_expand(x) #x
#define print_macro(x) printf("%s\n",macro_expand(x))
#define FOR(i,l,r) for(LL i=(l),i##ADJK=(r);i<=i##ADJK;++i)
#define ROF(i,r,l) for(LL i=(r),i##ADJK=(l);i>=i##ADJK;--i)
using namespace std;
typedef long long LL;
const LL MN=1e5+5,MM=2e5+5;
const LL inf=2e14;
LL N,M,T,tote;
struct E{
LL v,nxt;
LL flw;
E():v(0),nxt(0),flw(0){}
E(LL _v,LL _nxt,LL _flw):v(_v),nxt(_nxt),flw(_flw){}
}edge[MM*5*2];
LL head[MM*2+MN+2];
void AddE(LL u,LL v,LL f){
edge[++tote]=E(v,head[u],f);
head[u]=tote;
}
void Add(LL u,LL v,LL f){
AddE(u,v,f);
AddE(v,u,0);
}
LL s,t;
LL dis[MM*2+MN+2];
LL cur[MM*2+MN+2];
bool bfs(){
static const LL i_inf=1e9;
FOR(i,1,t)dis[i]=i_inf,cur[i]=head[i];
dis[s]=0;
queue<LL> Q;
Q.push(s);
while(Q.size()){
LL u=Q.front();
Q.pop();
for(LL p=head[u];p;p=edge[p].nxt){
LL v=edge[p].v;
if(edge[p].flw>0&&dis[v]>dis[u]+1){
dis[v]=dis[u]+1;
Q.push(v);
}
}
}
return dis[t]!=i_inf;
}
LL dfs(LL u,LL flw){
if(!flw)return 0;
if(u==t)return flw;
LL res=flw;
for(LL &p=cur[u];p;p=edge[p].nxt){
LL v=edge[p].v;
if(dis[v]!=dis[u]+1)continue;
LL tmp=0;
res-=(tmp=dfs(v,min(edge[p].flw,res)));
edge[p].flw-=tmp;
edge[p^1].flw+=tmp;
if(!res)return flw;
}
return flw-res;
}
bool ss[MM*2+MN+2];
void dfs(int u){
ss[u]=1;
for(int p=head[u];p;p=edge[p].nxt){
int v=edge[p].v;
if(edge[p].flw>0&&(!ss[v])){
dfs(v);
}
}
}
int main(){
freopen("antibody.in","r",stdin);
freopen("antibody.out","w",stdout);
scanf("%lld%lld%lld",&N,&M,&T);
tote=1;
LL sum=0;
s=N+2*M+1,t=N+2*M+2;
FOR(i,1,M){
LL u=0,v=0,w=0;
scanf("%lld%lld%lld",&u,&v,&w);
if(w<0)w=0;
Add(N+M+i,N+i,inf);
Add(v,N+M+i,inf);
Add(N+i,u,inf);
Add(s,N+i,w);
Add(N+M+i,t,w);
sum+=w;
}
LL ans=0;
while(bfs())ans+=dfs(s,inf);
ans=sum-ans;
printf("%lld\n",ans);
dfs(s);
// set<int> s;
// FOR(i,N+1,N+M)if(ss[i])cerr<<i-N<<" ";
// cerr<<endl;
// FOR(i,N+M+1,N+M+M)if(!ss[i])cerr<<i-N-M<<" ";
// cerr<<endl;
static int create[MM],totc;
FOR(i,N+1,N+M)if(ss[i]&&(!ss[i+M]))create[++totc]=i-N;
printf("%d\n",totc);
FOR(i,1,totc)printf("%d ",create[i]);
// printf("\n");
// system("grep VmPeak /proc/$PPID/status >/dev/tty");
fclose(stdin);
fclose(stdout);
return 0;
}
```cpp

浙公网安备 33010602011771号