C Pty loves lines
比赛的时候发现有很多区间是连续的,于是先打表看看。
n=699时的最后两个区间为[ 31098 , 31103 ] , [ 31105 , 243951 ]
n=700时的最后两个区间为[ 31145 , 31150 ] , [ 31152 , 244650 ]
观察得到31152之后的区间都是连续的,所以我们只要求出31152之前的每个交点数能不能存在即可。另dp[i][j]表示为 i 条直线是否可以组成 j 个交点。用bitset进行优化,时间复杂度为31152 * n * n / 32
AC Code
#include<bits/stdc++.h>
using namespace std;
const int N=31152;
bitset<N>f[701];
int main()
{
int t;
scanf("%d",&t);
f[0][0]=1;
for(int i=1;i<=700;i++)
{
for(int j=1;j<=i;j++)
f[i]|=f[i-j]<<(j*(i-j));
}
while(t--)
{
int n;
scanf("%d",&n);
int maxn=min(N-1,n*(n-1)/2);
printf("%d",0);
for(int i=1;i<=maxn;i++) if(f[n][i]) printf(" %d",i);
for(int i=N;i<=n*(n-1)/2;i++) printf(" %d",i);
printf("\n");
}
//system("pause");
return 0;
}
H. Pty loves string(补)
看到是前缀和后缀组成的串出现的次数首先想到的就是正反做两次kmp,然后就不知道该怎么做了。。。。。那么考虑一个出现位置S[l…r],会满足S[l…l+x-1]和S[1…x]相等,S[r-y+1…r]和S[n-y+1…n]相等,且l+x=r-y+1。以前缀为例,假设考虑当前位置为idx,那么第一个满足要求的前缀即为S[1…idx],然后是S[1…next[ idx ] ] ,然后是S[1…next [ next [ idx ] ] ] 。显然我们要用到border,当前点向该点的border连一条边,我们就得到了一棵树。正反做两次我们就得到了两棵树。
所以现在问题就转化成了给你两棵树,树上每个点都有一个值,然后每次询问给出的x和y两个子树,问两棵子树内有多少个点对(a,b)满足a+1=b。那么我们可以利用dfs序将树上问题转化为序列的区间问题。关键在于两棵树的形状不同,我们怎么将两边的值对应起来。我们可以先按照第一棵树的dfs序建主席树,然后每个dfs序 i 的权值对应着ans[i]+1 (ans[i]表示dfs序i对应的原来的值是多少) 在第二棵树上的dfs序。问题就转化成了在主席树上区间[la,ra]中查询范围为[lb,rb]的数的数量是多少。
AC Code
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
char str[N];
int n,q;
vector<int>g1[N],g2[N];
int nex1[N],nex2[N];
int dfn1[N],l1[N],r1[N],dfn2[N],l2[N],r2[N],ans[N];
int tot1,tot2,cnt,root[N];
struct node
{
int L,R;
int sum=0;
}tr[N*20];
void kmp1()
{
nex1[1]=0;
for(int i=2;i<=n;i++)
{
int j=nex1[i-1];
while(str[j+1]!=str[i]&&j>0) j=nex1[j];
if(str[j+1]==str[i]) nex1[i]=j+1;
else nex1[i]=0;
}
for(int i=1;i<=n;i++) g1[nex1[i]].push_back(i);
}
void kmp2()
{
nex2[n]=n+1;
for(int i=n-1;i>=1;i--)
{
int j=nex2[i+1];
while(str[j-1]!=str[i]&&j<=n) j=nex2[j];
if(str[j-1]==str[i]) nex2[i]=j-1;
else nex2[i]=n+1;
}
for(int i=1;i<=n;i++) g2[nex2[i]].push_back(i);
}
void dfs1(int x)
{
dfn1[x]=++tot1;
ans[tot1]=x;
l1[x]=tot1;
for(int i=0;i<g1[x].size();i++)
{
int to=g1[x][i];
dfs1(to);
}
r1[x]=tot1;
}
void dfs2(int x)
{
dfn2[x]=++tot2;
l2[x]=tot2;
for(int i=0;i<g2[x].size();i++)
{
int to=g2[x][i];
dfs2(to);
}
r2[x]=tot2;
}
void init()
{
for(int i=0;i<=n+1;i++) g1[i].clear(),g2[i].clear();
tot1=0,tot2=0;
cnt=1;
root[0]=0;
tr[0].L=tr[0].R=tr[0].sum=0;
}
void update(int num,int &rt,int l,int r)
{
tr[cnt++]=tr[rt];
rt=cnt-1;
tr[rt].sum++;
if(l==r) return ;
int mid=(l+r)/2;
if(num<=mid) update(num,tr[rt].L,l,mid);
else update(num,tr[rt].R,mid+1,r);
}
int query(int a,int b,int x,int y,int dl,int dr)
{
if(dl>=x&&dr<=y) return tr[b].sum-tr[a].sum;
int mid=(dl+dr)/2;
int res=0;
if(x<=mid) res=query(tr[a].L,tr[b].L,x,y,dl,mid);
if(y>mid) res+=query(tr[a].R,tr[b].R,x,y,mid+1,dr);
return res;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&q);
scanf("%s",str+1);
init();
kmp1(),kmp2();
dfs1(0);
dfs2(n+1);
for(int i=1;i<=n+1;i++)
{
root[i]=root[i-1];
update(dfn2[ans[i]+1],root[i],1,n+1);
}
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
printf("%d\n",query(root[l1[x]-1],root[r1[x]],l2[n-y+1],r2[n-y+1],1,n+1));
}
}
//system("pause");
return 0;
}