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);
}
}