比赛链接
感觉有点难想,而且要特判!
没想到正解并不算太难
没什么好说的,之前做过类似的题
时间复杂度 O ( n ln n ) O(n\ln n) O(nlnn)
#include
using namespace std;
const int N=1000100;
int n,siz[N],sum[N];
int e[N<<1],ne[N<<1],h[N],idx;
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void dfs(int u,int fa){
siz[u]=1;
for(int i=h[u];~i;i=ne[i]){
int v=e[i];if(v==fa) continue;
dfs(v,u),siz[u]+=siz[v];
}
}
void add(int x,int y){ e[idx]=y,ne[idx]=h[x],h[x]=idx++;}
int main(){
freopen("eat.in","r",stdin);
freopen("eat.out","w",stdout);
n=read();
memset(h,-1,sizeof(h));
for(int i=1;i<n;i++){
int x=read(),y=read();
add(x,y),add(y,x);
}
dfs(1,-1);
for(int i=1;i<=n;i++){
int g=siz[1]/__gcd(siz[1],siz[i]);
for(int j=g;j<=n;j+=g) sum[j]++;
}
int ans=0;
for(int i=1;i<=n;i++)
if(siz[1]%i==0) if(sum[i]>=i) ans++;
printf("%d\n",ans);
fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}
有些神的题
首先考虑 d p dp dp
但状态不好表示
我们想到这是一张每个点出度为 1 1 1 的图,那么前 i i i 个点一定会构成若干条链,那么我们不妨记 d p i , j dp_{i,j} dpi,j 为前 i i i 个点,构成了 j j j 条链的方案数
转移的话对当前点是 L
还是 R
分类讨论即可
询问 i i i 的答案的话合并前缀和后缀的 d p dp dp 数组即可
时间复杂度 O ( n 2 ) O(n^2) O(n2)
#include
using namespace std;
const int N=5100,P=1e9+7,inv2=500000004;
int n,fac[N],f[N][N],g[N][N];
char str[N];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
int main(){
freopen("jump.in","r",stdin);
freopen("jump.out","w",stdout);
n=read();scanf("%s",str+1);
if(n==1){ puts("1");exit(0);}
f[0][0]=1;
for(int i=1;i<=n;i++){
if(str[i]=='L')
for(int j=1;j<=i;j++)
f[i][j]=(1ll*f[i-1][j+1]*(j+1)%P*j+1ll*f[i-1][j]*j)%P;
else
for(int j=1;j<=i;j++)
f[i][j]=(f[i-1][j-1]+1ll*f[i-1][j]*j)%P;
}
g[n+1][0]=1;
for(int i=n;i;i--){
if(str[i]=='R')
for(int j=1;j<=n-i+1;j++)
g[i][j]=(1ll*g[i+1][j+1]*(j+1)%P*j+1ll*g[i+1][j]*j)%P;
else
for(int j=1;j<=n-i+1;j++)
g[i][j]=(g[i+1][j-1]+1ll*g[i+1][j]*j)%P;
}
fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%P;
printf("%d ",g[2][1]);
for(int i=2;i<n;i++){
int ans=0;
for(int j=1;j<i;j++){
int coef1=1ll*f[i-1][j]*g[i+1][j+1]%P*fac[j+1]%P*fac[j]%P;
int coef2=1ll*f[i-1][j]*g[i+1][j]%P*fac[j]%P*fac[j]*2%P;
int coef3=1ll*f[i-1][j]*g[i+1][j-1]%P*fac[j]%P*fac[j-1]%P;
ans=(1ll*ans+coef1+coef2+coef3)%P;
}
printf("%d ",ans);
}
printf("%d\n",f[n-1][1]);
fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}
我们考虑如何判断一个子矩形不存在两个黑色连通块(假设我们保证它不存在空腔)
我们把每列中极大的黑色相邻块缩成一个点,然后列与列直接相邻的点之间连边
如果这个图是一颗树,即 ∣ V ∣ = ∣ E ∣ + 1 |V|=|E|+1 ∣V∣=∣E∣+1,那么它就合法
我们考虑搜出所有的空腔的,然后在 ( x 2 + 1 , y 2 + 1 ) (x_2+1,y_2+1) (x2+1,y2+1) 打 y 1 − 1 y_1-1 y1−1 的 t a g tag tag,不难发现直接双指针 + 桶维护即可
时间复杂度 O ( n 3 ) O(n^3) O(n3)
#include
#define pb push_back
using namespace std;
typedef long long LL;
const int N=310;
int n,m,mnx,mny,mxx,mxy;
char str[N];
bool a[N][N],vis[N][N];
struct Node{ int x1,x2,y1,y2;};
vector<Node> tag[N];
vector<int> tg[N][N];
int fx[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
void dfs(int x,int y){
mnx=min(mnx,x),mny=min(mny,y),mxx=max(mxx,x),mxy=max(mxy,y);
vis[x][y]=1;
for(int k=0;k<4;k++){
int tx=x+fx[k][0],ty=y+fx[k][1];
if(tx<1||tx>n||ty<1||ty>m||a[tx][ty]||vis[tx][ty]) continue;
dfs(tx,ty);
}
}
int buc[N*N],totV[N],totE[N],B[N];
int main(){
freopen("village.in","r",stdin);
freopen("village.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;i++){
scanf("%s",str+1);
for(int j=1;j<=m;j++) a[i][j]=str[j]-48;
}
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!a[i][j]&&!vis[i][j]&&(i==1||i==n||j==1||j==m)) dfs(i,j);
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!a[i][j]&&!vis[i][j]){
mnx=1e9,mny=1e9,mxx=0,mxy=0;
dfs(i,j);
tag[mnx-1].pb({mnx,mxx,mny,mxy});
}
int Delta=n+5;
LL ans=0;
for(int u=n;u>=1;u--){
for(Node t:tag[u]) tg[t.x2+1][t.y2+1].pb(t.y1-1);
memset(totV,0,sizeof(totV));
memset(totE,0,sizeof(totE));
memset(B,0,sizeof(B));
for(int d=u;d<=n;d++){
for(int i=1;i<=m;i++)
if(a[d][i]&&(d==u||!a[d-1][i])){
totV[i]++;
if(a[d][i-1]) totE[i]++;
if(a[d][i+1]&&!(d==u||!a[d-1][i+1])) totE[i+1]++;
}
for(int i=1;i<=m;i++) totV[i]+=totV[i-1],totE[i]+=totE[i-1];
buc[totV[0]-totE[1]+Delta]++;
assert(totV[0]-totE[1]+Delta>=0),assert(totV[0]-totE[1]+Delta<(N<<1));
for(int i=1,j=0;i<=m;i++){
for(int t:tg[d][i]) B[i]=max(B[i],t);
while(j<B[i]){ buc[totV[j]-totE[j+1]+Delta]--;j++;}
assert(totV[i]-totE[i]-1+Delta>=0),assert(totV[i]-totE[i]-1+Delta<N*N);
ans+=buc[totV[i]-totE[i]-1+Delta];
if(i<m){
assert(totV[i]-totE[i+1]+Delta>=0),assert(totV[i]-totE[i+1]+Delta<N*N);
buc[totV[i]-totE[i+1]+Delta]++;
}
}
for(int i=0;i<m;i++) buc[totV[i]-totE[i+1]+Delta]=0;
for(int i=m;i;i--) totV[i]-=totV[i-1],totE[i]-=totE[i-1];
for(int i=1;i<=m;i++) B[i]=max(B[i],B[i-1]);
}
}
printf("%lld\n",ans);
fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}