4.13省选模拟
这是博客园的第一百篇随笔\(!\)
不说别的,感觉代码能力真的提升很大,认真敲代码真的很畅快,好嘛\(!\)
一个原来的信竞生送来了一个省选祝福吧,感觉一句话说的很好
能走到现在,你们早已是赢家,抛去世界的一切,这一次,是为自己而战
\(T1\)
考场上一眼看出来正解,半平面交不会写,就造了一个假的半平面交。。(复杂度不对)
考场暴力代码(有一些细节也没处理好,考场上写了\(240+\))
#include<bits/stdc++.h>
#define int long long
#define MAXN 200005
#define INF 1e30
using namespace std;
int sta[MAXN],son[MAXN],top1[MAXN],zx[MAXN][20],f[MAXN],top;
int head[MAXN],nxt[MAXN],to[MAXN],tot;
int n,m,cnt,siz[MAXN],dep[MAXN];
struct node
{
int a,s,id;
}poz[MAXN];
struct LINE
{
int k,st,ed,id,js,qs;
}Line[MAXN];
void add(int u,int v)
{
tot++;
to[tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
bool cmp(node x,node y)
{
if(x.a!=y.a) return x.a<y.a;
return x.id<y.id;
}
void dfs_pre(int now,int fa)
{
zx[now][0]=fa;
for(int i=1;i<=18;i++)
{
zx[now][i]=zx[zx[now][i-1]][i-1];
}
int maxn=-1;
dep[now]=dep[fa]+1;
siz[now]=1;
f[now]=fa;
for(int i=head[now];i;i=nxt[i])
{
int y=to[i];
if(y==fa) continue;
dfs_pre(y,now);
siz[now]+=siz[y];
if(siz[y]>maxn)
{
maxn=siz[y];
son[now]=y;
}
}
}
void dfs_top(int now,int topn)
{
top1[now]=topn;
if(!son[now]) return ;
dfs_top(son[now],topn);
for(int i=head[now];i;i=nxt[i])
{
int y=to[i];
if(top1[y]) continue;
dfs_top(y,y);
}
}
int LCA(int x,int y)
{
while(top1[x]!=top1[y])
{
if(dep[top1[x]]<dep[top1[y]]) swap(x,y);
x=f[top1[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
int LEN(int x,int y)
{
return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
int Find(int now,int dp)
{
for(int i=18;i>=0;i--)
{
if((dp>>i)&1) now=zx[now][i];
}
return now;
}
//注意编号顺序
signed main()
{
freopen("ant.in","r",stdin);
freopen("ckant.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&poz[i].s);
poz[i].id=i;
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&poz[i].a);
}
// for(int i=1;i<=n;i++)
// {
// poz[i].s+=poz[i].a;
// }
sort(poz+1,poz+1+n,cmp);
int top=0;
for(int i=1;i<=n;i++)
{
while(top&&poz[sta[top]].s<=poz[i].s) top--;
sta[++top]=i;
}
// for(int i=1;i<=top;i++)
// {
// cout<<"id: "<<poz[sta[i]].id<<"\n";
// }
Line[cnt=1].id=poz[sta[1]].id;
Line[cnt=1].st=0;
int l=1;
// cout<<top<<endl;
// return 0;
while(l<top)
{
// cout<<l<<"\n";
// cout<<poz[sta[l]].a<<"\n";
int jd=INF,xz;
int s=poz[sta[l]].s;
int a=poz[sta[l]].a;
for(int i=l+1;i<=top;i++)
{
int s2=poz[sta[i]].s;
int a2=poz[sta[i]].a;
int x=ceil((s2-s)*1.0/(a-a2)*1.0);
if(s+x*a==s2+x*a2)
{
if(poz[sta[l]].id>poz[sta[i]].id)
{
x++;
}
}
if(x<jd)
{
jd=x;
xz=i;
}
else if(x==jd&&poz[sta[i]].s+x*poz[sta[i]].a>=poz[sta[xz]].s+x*poz[sta[xz]].a)
{
jd=x;
xz=i;
}
// cout<<"jd: "<<jd<<"\n";
}
Line[cnt].ed=jd-1;
++cnt;
Line[cnt].id=poz[sta[xz]].id;
Line[cnt].st=jd;
Line[cnt].k=poz[sta[xz]].a;
l=xz;
// cout<<"xz: "<<xz<<" "<<poz[sta[xz]].id<<"\n";
}
Line[cnt].ed=INF;
for(int i=1,u,v;i<n;i++)
{
scanf("%lld%lld",&u,&v); u++; v++;
add(u,v); add(v,u);
}
dfs_pre(1,1);
dfs_top(1,1);
int now=1;
Line[0].js=1;
for(int i=1;i<=cnt;i++)
{
Line[i].qs=Line[i-1].js;
int id=Line[i].id;
int Len=LEN(now,id);
int lca=LCA(now,id);
int MidLen=LEN(now,LCA(now,id));
int TimLen=Line[i].ed-Line[i].st+1;
if(TimLen<MidLen)
{
Line[i].js=Find(Line[i].qs,TimLen);
}
else if(TimLen==MidLen)
{
Line[i].js=lca;
}
else if(TimLen>MidLen&&TimLen<Len)
{
TimLen-=MidLen;
Line[i].js=Find(id,LEN(id,lca)-TimLen);
}
else
{
Line[i].js=id;
}
now=Line[i].js;
// cout<<"poi: "<<i<<" "<<Line[i].qs<<" "<<Line[i].js<<"\n";
}
for(int i=1,T;i<=m;i++)
{
scanf("%lld",&T);
int l=1,r=cnt,mid,ans;
while(l<=r)
{
mid=(l+r)>>1;
if(Line[mid].ed>=T-1)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
// cout<<"mid: "<<ans<<"\n";
int Ans;
int id=Line[ans].js;
int now=Line[ans].qs;
int Len=LEN(id,now);
int lca=LCA(now,id);
int TimLen=T-Line[ans].st;
int MidLen=LEN(now,LCA(now,id));
if(TimLen<MidLen)
{
Ans=Find(Line[ans].qs,TimLen);
}
else if(TimLen==MidLen)
{
Ans=LCA(now,id);
}
else if(TimLen>MidLen&&TimLen<Len)
{
TimLen-=MidLen;
Ans=Find(id,LEN(id,lca)-TimLen);
}
else
{
Ans=id;
}
printf("%lld\n",Ans-1);
// cout<<Ans-1<<"\n";
}
}
考后重写了一遍半平面交,改了改就过了
#include<bits/stdc++.h>
#define int long long
#define MAXN 200005
#define INF 1e30
using namespace std;
int sta[MAXN],son[MAXN],top1[MAXN],zx[MAXN][20],f[MAXN],top;
int head[MAXN],nxt[MAXN],to[MAXN],tot;
int n,m,siz[MAXN],dep[MAXN];
struct node
{
int k,b,id;
}poz[MAXN],T[MAXN];
struct line
{
int st,ed,id,js,qs;
}Line[MAXN];
bool cmp(node a,node b)
{
if(a.k!=b.k) return a.k<b.k;
if(a.b!=b.b) return a.b>b.b;
return a.id>b.id;
}
int Get(node l1,node l2)
{
int x=ceil((l2.b-l1.b)*1.0/(l1.k-l2.k)*1.0);
if(l1.k*x+l1.b==l2.k*x+l2.b)
{
if(l1.id>l2.id) x++;
}
return x;
}
void add(int u,int v)
{
tot++;
to[tot]=v;
nxt[tot]=head[u];
head[u]=tot;
}
void dfs_pre(int now,int fa)
{
zx[now][0]=fa;
for(int i=1;i<=18;i++)
{
zx[now][i]=zx[zx[now][i-1]][i-1];
}
int maxn=-1;
dep[now]=dep[fa]+1;
siz[now]=1;
f[now]=fa;
for(int i=head[now];i;i=nxt[i])
{
int y=to[i];
if(y==fa) continue;
dfs_pre(y,now);
siz[now]+=siz[y];
if(siz[y]>maxn)
{
maxn=siz[y];
son[now]=y;
}
}
}
void dfs_top(int now,int topn)
{
top1[now]=topn;
if(!son[now]) return ;
dfs_top(son[now],topn);
for(int i=head[now];i;i=nxt[i])
{
int y=to[i];
if(top1[y]) continue;
dfs_top(y,y);
}
}
int LCA(int x,int y)
{
while(top1[x]!=top1[y])
{
if(dep[top1[x]]<dep[top1[y]]) swap(x,y);
x=f[top1[x]];
}
if(dep[x]>dep[y]) swap(x,y);
return x;
}
int LEN(int x,int y)
{
return dep[x]+dep[y]-2*dep[LCA(x,y)];
}
int Find(int now,int dp)
{
for(int i=18;i>=0;i--)
{
if((dp>>i)&1) now=zx[now][i];
}
return now;
}
signed main()
{
freopen("ant.in","r",stdin);
freopen("ant.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%lld",&poz[i].b);
poz[i].id=i;
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&poz[i].k);
}
sort(poz+1,poz+1+n,cmp);
T[top=1]=poz[1];
for(int i=2;i<=n;i++)
{
if(poz[i].k==poz[i-1].k) continue;
while(top>1&&(Get(T[top-1],poz[i])<Get(T[top-1],T[top])||(poz[i].k*Get(T[top-1],poz[i])+poz[i].b>T[top].k*Get(T[top-1],poz[i])+T[top].b&&Get(T[top-1],poz[i])==Get(T[top-1],T[top])))) top--;
T[++top]=poz[i];
}
Line[0].ed=-1;
for(int i=1;i<=top;i++)
{
Line[i].id=T[i].id;
Line[i].st=Line[i-1].ed+1;
if(i!=top) Line[i].ed=Get(T[i],T[i+1])-1;
}
Line[top].ed=INF;
// for(int i=1;i<=top;i++)
// {
// cout<<Line[i].id<<" "<<Line[i].st<<" "<<Line[i].ed<<"\n";
// }
// return 0;
for(int i=1,u,v;i<n;i++)
{
scanf("%lld%lld",&u,&v); u++; v++;
add(u,v); add(v,u);
}
dfs_pre(1,1);
dfs_top(1,1);
int now=1;
Line[0].js=1;
for(int i=1;i<=top;i++)
{
Line[i].qs=Line[i-1].js;
int id=Line[i].id;
int Len=LEN(now,id);
int lca=LCA(now,id);
int MidLen=LEN(now,LCA(now,id));
int TimLen=Line[i].ed-Line[i].st+1;
if(TimLen<MidLen)
{
Line[i].js=Find(Line[i].qs,TimLen);
}
else if(TimLen==MidLen)
{
Line[i].js=lca;
}
else if(TimLen>MidLen&&TimLen<Len)
{
TimLen-=MidLen;
Line[i].js=Find(id,LEN(id,lca)-TimLen);
}
else
{
Line[i].js=id;
}
now=Line[i].js;
// cout<<"poi: "<<i<<" "<<Line[i].qs<<" "<<Line[i].js<<"\n";
}
for(int i=1,T;i<=m;i++)
{
scanf("%lld",&T);
int l=1,r=top,mid,ans;
while(l<=r)
{
mid=(l+r)>>1;
if(Line[mid].ed>=T-1)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
// cout<<"mid: "<<ans<<"\n";
int Ans;
int id=Line[ans].js;
int now=Line[ans].qs;
int Len=LEN(id,now);
int lca=LCA(now,id);
int TimLen=T-Line[ans].st;
int MidLen=LEN(now,LCA(now,id));
if(TimLen<MidLen)
{
Ans=Find(Line[ans].qs,TimLen);
}
else if(TimLen==MidLen)
{
Ans=LCA(now,id);
}
else if(TimLen>MidLen&&TimLen<Len)
{
TimLen-=MidLen;
Ans=Find(id,LEN(id,lca)-TimLen);
}
else
{
Ans=id;
}
printf("%lld\n",Ans-1);
}
}
\(T2\)
大力插头\(dp\)即可
源自题解.......
#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
const int x5[10]={1,5,25,125,625,3125,15625,78125};
int v,past,now;
int f[2][480000],n,m,k,s[100][10],x,y,all;
int b[480000][9];
void out()
{
for (int k=0;k<all;k++) if (f[past][k])
{
for (int j=0;j<=m;j++) printf("%d",b[k][j]);
printf(":%d\n",f[past][k]);
}
}
inline void add(int &a) {a+=v,a%=mod;}
void init()
{
all=6;
for (int i=0;i<m;i++) all*=5;
for (int i=0;i<all;i++)
{
int temp=i;
for (int j=0;j<m;j++) b[i][j]=temp%5,temp/=5;
b[i][m]=temp;
}
}
int main()
{
freopen("tetris.in","r",stdin);
freopen("tetris.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
while (k--)
{
scanf("%d%d",&x,&y);
s[x][y]=1;
}
init();
now=0,past=1;
f[now][0]=1;
for (int i=0;i<n;i++)
for (int j=0;j<m;j++)
{
swap(now,past);
memset(f[now],0,sizeof f[now]);
//printf("%d %d\n",i,j);
//out();
for (int k=0;k<all;k++)
{
v=f[past][k];
if (!v) continue;
if (!j && b[k][m]) continue;
if (s[i][j])
{
if (!b[k][m] && !b[k][j]) add(f[now][k]);
continue;
}
int gao=1,temp=k-b[k][m]*x5[m]-b[k][j]*x5[j];
if (b[k][m] && b[k][j])
{
if (b[k][m]==5) continue;
if (b[k][m]==4) gao+=2;else gao+=4-b[k][m];
if (b[k][j]==4) gao+=2;else gao+=4-b[k][j];
if (gao==4) add(f[now][temp]);
else if (gao<4)add(f[now][temp+x5[j]]),add(f[now][temp+x5[m]]);
}
else if (b[k][m])
{
if (b[k][m]==3)
add(f[now][temp+x5[j]+x5[m]]),
add(f[now][temp+x5[j]*2]),
add(f[now][temp+x5[m]*2]);
if (b[k][m]==5 || b[k][m]==2)
add(f[now][temp+x5[j]]),
add(f[now][temp+x5[m]]);
if (b[k][m]==4)
add(f[now][temp+x5[m]]);
if (b[k][m]==1)
add(f[now][temp]);
}
else if (b[k][j])
{
if (b[k][j]==3)
add(f[now][temp+x5[j]+x5[m]]),
add(f[now][temp+x5[j]*2]),
add(f[now][temp+x5[m]*5]);
if (b[k][j]==2)
add(f[now][temp+x5[j]]),
add(f[now][temp+x5[m]]);
if (b[k][j]==4)
add(f[now][temp+x5[j]]);
if (b[k][j]==1)
add(f[now][temp]);
}
else
{
add(f[now][temp+x5[j]*3]);
add(f[now][temp+x5[j]*4+x5[m]]);
add(f[now][temp+x5[j]+x5[m]*4]);
add(f[now][temp+x5[m]*3]);
}
}
}
printf("%d\n",f[now][0]);
}
\(T3\)
计数题
如果把各种知识放在一起考虑,那么很麻烦,我们可以考虑一个一个知识去算,然后最后进行一下容斥操作
\(f(k)\)表示前\(k\)道题会做,后\(n-k\)道题不一定的方案数
\(g(k)\)表示前\(k\)道题会做,后\(n-k\)道题不会做的方案数
比较显然,\(f(k)\)包含\(g(k),\)我们需要把\(g(k)\)容斥出来
还是较为套路的二项式反演
\(f(k)=\sum C(j,k) g(j)\)
\(g(k)=\sum (-1)^{j-k} f(j)\)
我们考虑求\(f(x)\)可以把各种知识分开考虑,最后乘起来
我一直再想,这个会不会出现,前面符合要求,后面不符合要求的情况
其实我们每一步都是保证前\(n-k\)个,可以符合条件的方案,我一开始以为最后还要交换顺序之类的
就想的过于麻烦了,然后最后大概就是枚举\(Q\)每一个知识点的实力,最后相乘就好了
至于为什么二项式反演,我们强制让后面都严格大于不可以吗\(?\)
考虑最后他要会做这道题,那么就是说,我们总的中位数要满足条件
但是又说,我们这个即使前\(k\)个这个知识点会做,后面知识点的也不一定满足,这就是我们二项式容斥的必要我们最后\(f(k)\)表示的是全部知识点的情况
考虑每一种知识的时候,我们可以枚举\(Q\)的水平,假设为\(x,\)我们有一个\(a\)的范围使得既满足前\(n-k\)可做,后面的可能不可做,但是这道题会做...(有点混乱)
我们让\((n+1)/2<=a+k<=n\)
最后保留\(x,\)求出多项式系数,然后把多项式乘起来就好了
#include<bits/stdc++.h>
#define mod 1000000007
#define int long long
#define maxn 102
using namespace std;
int C[105][105];
int sigma[105][105];
int n,m,k,u[105],p[105][105];
int ji;
int sqr(int x) {return (x*x)%mod;}
int qming(int a,int b)
{
if (!b) return 1;
if (b&1) return (sqr(qming(a,b>>1))*a)%mod;
return sqr(qming(a,b>>1));
}
void initC()
{
C[0][0]=1;
C[1][0]=C[1][1]=1;
for (int i=2;i<=maxn;i++)
{
C[i][0]=C[i][i]=1;
for (int j=1;j<i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j],C[i][j]%=mod;
}
}
void initp()
{
ji=1;
for (int i=0;i<m;i++) ji*=u[i],ji%=mod;
int temp;
for (int i=0;i<m;i++)
{
p[i][0]=1;
for (int j=1;j<=maxn;j++)
{
temp=p[i][j-1];
temp*=u[i];
temp%=mod;
p[i][j]=temp;
}
}
}
void initsigma()
{
int temp;
sigma[0][1]=1;
for (int i=1;i<=maxn;i++)
{
sigma[i][i+1]=1;
for (int j=0;j<i;j++)
for (int k=1;k<=j+1;k++)
{
temp=C[i+1][j];
temp*=sigma[j][k];
temp%=mod;
if (((i-j)&1)==0) temp=mod-temp;
sigma[i][k]+=temp%mod;
sigma[i][k]%=mod;
}
int chu=qming(i+1,mod-2);
for (int k=1;k<=i+1;k++)
{
temp=sigma[i][k];
temp*=chu;
sigma[i][k]=temp%mod;
}
}
}
int f[105];
int sigmaf[105];
int count(int x,int t)
{
int ret=0,now=1,temp;
for (int i=0;i<=t;i++)
{
ret+=now*sigmaf[i];
ret%=mod;
now*=x;
now%=mod;
}
return ret;
}
void getsigmaf(int t)
{
memset(sigmaf,0,sizeof sigmaf);
int temp;
for (int i=0;i<=t;i++)
{
for (int j=1;j<=i+1;j++)
{
temp=f[i];
temp*=sigma[i][j];
temp%=mod;
sigmaf[j]+=temp;
sigmaf[j]%=mod;
}
}
}
int solve(int k)
{
int ret=1,temp;
int a=n-k;
int b=(n+1)/2;
b-=k;
b=max(b,0ll);
for (int o=0;o<m;o++)
{
memset(f,0,sizeof f);
for (int i=b;i<=a;i++)
{
for (int j=0;j<=a-i;j++)
{
temp=C[a-i][j];
temp*=p[o][a-i-j];
temp%=mod;
if (j&1) temp=mod-temp;
temp*=C[a][i];
temp%=mod;
f[j+i+k]+=temp;
f[j+i+k]%=mod;
}
}
getsigmaf(n);
ret*=count(u[o],n+1);
ret%=mod;
}
//ret*=qming(ji,k);
//ret%=mod;
return ret;
}
signed main()
{
// freopen("problem.in","r",stdin);
// freopen("problem.out","w",stdout);
initC();
initsigma();
int T;
scanf("%lld",&T);
while (T--)
{
scanf("%lld%lld%lld",&m,&n,&k);
for (int i=0;i<m;i++) scanf("%lld",u+i);
initp();
int ans=0,bj=1;
int temp;
for (int i=k;i<=n;i++)
{
temp=solve(i);
temp*=C[n-k][i-k];
ans+=bj*temp;
ans%=mod;
if (ans<0) ans+=mod;
bj*=-1;
}
printf("%lld\n",ans);
}
}