C:
直接将每个数-i,那么就是求中位数。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const LL inf=1LL<<60;
LL n,a[200010];
int main()
{
scanf("%lld",&n);
for(LL i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]-=i;
sort(a+1,a+n+1);
LL ans=0;
for(LL i=1;i<=n;i++) ans+=abs(a[i]-a[n/2+1]);
printf("%lld",ans);
return 0;
}
D:
猜了个不会证的结论,枚举中间的刀,那么两边变成了子问题,显然两边最优时全局最优
容易发现两边的切点都是单调的,扫一遍即可。
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#define LL long long
using namespace std;
const LL inf=1LL<<60;
LL n,a[200010],sum[200010],ans=inf;
LL k1,k2,p;
void solve()
{
LL t1=max(max(sum[k1],sum[p]-sum[k1]),max(sum[k2]-sum[p],sum[n]-sum[k2]));
LL t2=min(min(sum[k1],sum[p]-sum[k1]),min(sum[k2]-sum[p],sum[n]-sum[k2]));
ans=min(ans,t1-t2);
}
int main()
{
scanf("%lld",&n);
for(LL i=1;i<=n;i++) scanf("%lld",&a[i]);
for(LL i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
k1=1;p=2;k2=3;
while(k2<n-1&&abs(sum[k2]-sum[p]-(sum[n]-sum[k2]))>=abs(sum[k2+1]-sum[p]-(sum[n]-sum[k2+1]))) k2++;
solve();
while(p<n-2)
{
p++;if(k2==p) k2++;
while(k1<p-1&&abs(sum[p]-sum[k1]-sum[k1])>=abs(sum[p]-sum[k1+1]-sum[k1+1])) k1++;
while(k2<n-1&&abs(sum[k2]-sum[p]-(sum[n]-sum[k2]))>=abs(sum[k2+1]-sum[p]-(sum[n]-sum[k2+1]))) k2++;
solve();
}
printf("%lld",ans);
}
E:
n
3
n^3
n3做法显然,状压F[S]表示S的子集中的最大值和次大值。
然后的sb否掉,写了可持久化trie 调了一下午
其实只要枚举数位,去掉1,就可以了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=1<<28;
int N=17;
struct node{
int c1,k1,c2,k2;
node() {c1=c2=-inf;}
};
struct trnode{
int lc,rc;
node c;
}tr[6000010];int root=0,tot=0;
int a[300010];
node operator + (node c1,node c2)
{
node ans;
if(c1.c1>c2.c1)
{
ans.c1=c1.c1;ans.k1=c1.k1;
if(c1.c2>c2.c2) ans.c2=c1.c2,ans.k2=c1.k2;
else ans.c2=c2.c2,ans.k2=c2.k2;
if(c2.k1!=ans.k1&&c2.c1>ans.c2) ans.c2=c2.c1,ans.k2=c2.k1;
}
else
{
ans.c1=c2.c1;ans.k1=c2.k1;
if(c1.c2>c2.c2) ans.c2=c1.c2,ans.k2=c1.k2;
else ans.c2=c2.c2,ans.k2=c2.k2;
if(c1.k1!=ans.k1&&c1.c1>ans.c2) ans.c2=c1.c1,ans.k2=c1.k1;
}
return ans;
}
int n;
void insert(int &x,int c,int d,int v,int num)
{
if(!x) x=++tot;
if(d==-1) {node t;t.c1=v;t.k1=num;t.c2=-inf;tr[x].c=tr[x].c+t;return;}
int op=(c&(1<<d))?1:0;
if(op) insert(tr[x].lc,c,d-1,v,num);
else insert(tr[x].rc,c,d-1,v,num);
tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c;
}
bool flag=false;
int merge(int x1,int x2,int d)
{
int x=++tot;
if(d!=-1) tr[x1].c=tr[tr[x1].lc].c+tr[tr[x1].rc].c;
if(d!=-1) tr[x2].c=tr[tr[x2].lc].c+tr[tr[x2].rc].c;
if(!x1||!x2) tr[x]=tr[x1+x2];
else if(d==-1) tr[x].c=tr[x1].c+tr[x2].c;
else
{
tr[x].lc=merge(tr[x1].lc,tr[x2].lc,d-1);
tr[x].rc=merge(tr[x1].rc,tr[x2].rc,d-1);
tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c;
}
return x;
}
void dfs(int x,int d)
{
if(!x||d==-1) return;
dfs(tr[x].lc,d-1);dfs(tr[x].rc,d-1);
tr[x].lc=merge(tr[x].lc,tr[x].rc,d-1);
tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<1<<n;i++) scanf("%d",&a[i]),insert(root,i,N,a[i],i);
dfs(root,N);
for(int i=1;i<(1<<n)-1;i++)
{
int x=root,ans=-inf,k=i+1;
for(int j=N;j>=0;j--)
{
int c=(k&(1<<j))?1:0;
if(c) ans=max(ans,tr[tr[x].rc].c.c1+tr[tr[x].rc].c.c2),x=tr[x].lc;
else x=tr[x].rc;
}
printf("%d\n",ans);
}
printf("%d",tr[root].c.c1+tr[root].c.c2);
}
F:
目前为止做过最简单的F
先考虑怎么计算好串,感觉算不好串好写些,直接dp
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示前i位最后j位互不相同。
然后要求这些串包含
A
A
A,枚举A出现的位置,然后再计数。
假如
A
A
A中出现了长度为
K
K
K的互不相同子串,
a
n
s
=
(
n
−
m
+
1
)
∗
k
m
−
n
ans=(n-m+1)*k^{m-n}
ans=(n−m+1)∗km−n
假如
A
A
A中有重复的数字,那么前后互不影响,分别求出两边合并即可。
最后一种情况因为前后互相影响,所以不能分开算。因为元素之间是没有区别的,那么我们可以先求出在所有不好的序列中,有多少个长度为m的子串满足其中元素两两不同,这个用上面的dp改改就好了,最后除以
k
!
(
k
−
m
)
!
\frac{k!}{(k-m)!}
(k−m)!k!
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define LL long long
using namespace std;
const LL mod=1e9+7;
LL pow(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1) ans=(LL)ans*a%mod;
a=(LL)a*a%mod;b>>=1;
}
return ans;
}
LL n,k,m,a[25010],last[410],p[25010],l[25010];
LL ans=0,f[2][25010][410],sum[410],fac[410],inv[410];
void dp(LL op,LL len)
{
f[op][0][len]=1;
for(LL i=1;i<=n;i++)
{
sum[0]=0;for(LL j=1;j<k;j++) sum[j]=(sum[j-1]+f[op][i-1][j])%mod;
for(LL j=1;j<k;j++) f[op][i][j]=((sum[k-1]-sum[j-1])%mod+f[op][i-1][j-1]*(k-j+1)%mod)%mod;
}
}
void pre()
{
fac[0]=fac[1]=inv[0]=inv[1]=1;
for(LL i=2;i<=400;i++) fac[i]=(LL)fac[i-1]*i%mod,inv[i]=pow(fac[i],mod-2);
}
int main()
{
pre();
scanf("%lld %lld %lld",&n,&k,&m);
for(LL i=1;i<=m;i++)
{
scanf("%lld",&a[i]);
p[i]=last[a[i]];last[a[i]]=i;
}
LL t=0;bool flag=false;
for(LL i=1;i<=m;i++)
{
t=max(t,p[i]+1);
l[i]=t;if(i-l[i]+1==k) flag=true;
}
if(flag)
{
for(LL i=0;i<=n-m;i++) (ans+=(LL)pow(k,i)*pow(k,n-m-i)%mod)%=mod;
printf("%lld",ans);return 0;
}
for(LL i=1;i<=m;i++) if(l[i]==1) t=i;
if(t==m)
{
dp(0,0);
for(LL i=1;i<=n;i++)
{
sum[0]=0;for(LL j=1;j<k;j++) sum[j]=(sum[j-1]+f[1][i-1][j])%mod;
for(LL j=1;j<k;j++)
{
f[1][i][j]=((sum[k-1]-sum[j-1])%mod+f[1][i-1][j-1]*(k-j+1)%mod)%mod;
if(j>=m) (f[1][i][j]+=f[0][i][j])%=mod;
}
//sum[0]=0;for(LL j=1;j<k;j++) sum[j]=((sum[j-1]+f[1][i-1][j])%mod+f[0][i-1][j])%mod;
//for(LL j=m;j<k;j++) f[1][i][j]=((sum[k-1]-sum[j-1])%mod+(f[1][i-1][j-1]+f[0][i-1][j-1]*(k-j+1)%mod)%mod)%mod;
}
LL ans=0,tot=(LL)(n-m+1)*pow(k,n-m)%mod;
for(LL i=1;i<k;i++) (ans+=(LL)f[1][n][i])%=mod;
ans=(LL)ans*fac[k-m]%mod*inv[k]%mod;
(tot-=ans)%=mod;
printf("%lld",(tot+mod)%mod);
return 0;
}
dp(0,t);dp(1,m-l[m]+1);
for(LL i=0;i<=n-m;i++)
{
t=(LL)pow(k,i)*pow(k,n-m-i)%mod;
LL k1=0,k2=0;
for(LL j=1;j<k;j++) (k1+=f[0][i][j])%=mod,(k2+=f[1][n-m-i][j])%=mod;
(ans+=(t-(LL)k1*k2%mod)%mod)%=mod;
}
printf("%lld",(ans+mod)%mod);
}