noi.ac NOI挑战营模拟赛1-5
注:因为博主是个每次考试都爆零垫底的菜鸡,所以此篇博客很有可能咕咕咕
(指只贴AC代码不写题解的......如果我真的不会做的话,就不能怪我了qwqwq)
Day1
T1 swap
- 23pts 从一个状态开始爆搜,然后我们哈希一下状态,保证一个状态只被访问一次。时间复杂度\(O(n!n)\),感觉复杂度过55分没问题,但是到后面会RE.......不知为何呀QAQ
- 55pts 枚举一下这个之后的排列,然后我们再通过判断一下每两个宽度大于n的人没有没更换相对位置来判断该结束状态的合法性(相对位置指如果原先pos_x<pos_y,之后pos_x仍然小于pos_y)。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define MAXN 100010
using namespace std;
int n,m,tot,ans;
int a[MAXN],pos[MAXN];
struct Line{int u,v;}line[MAXN<<1];
inline bool check()
{
for(int i=1;i<=tot;i++)
if(pos[line[i].u]>pos[line[i].v]) return false;
return true;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(a[i]+a[j]>m)
line[++tot]=(Line){i,j};
for(int i=1;i<=n;i++) pos[i]=i;
do{
if(check()==true) ans++;
}while(next_permutation(&pos[1],&pos[n+1]));
printf("%d\n",ans);
return 0;
}
满分做法比较神仙,就是我们从小到大处理。对于当前最小的数,我们判断它和当前最大的数能不能交换;
如果它和最大的可以交换,那么它和当前数列里面的所有数都可以交换(意思是最后的位置有 当前序列中数的数量-->n 种)所以我们可以给答案乘上n,然后去掉这个最小数,对于剩下的序列递归计算(因为最后无论这个子序列是什么情况,最小数都可以以n种方式插入到它们中间构成答案);
如果它不能和最大的交换,那么最大的就无法和当前序列中任意一个数交换,所以它就没用了,只有在它当前位置上那一种贡献,我们删去它,递归处理子序列即可。
- 100pts
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<algorithm>
#define MAXN 100010
#define mod 1000000007
using namespace std;
int n,m;
int a[MAXN];
vector<int>vec;
inline int solve(vector<int>x)
{
// for(int i=0;i<x.size();i++) printf("%d ",x[i]); puts("");
if(x.size()<=1) return 1;
int min_pos,max_pos,minn=0x3f3f3f3f,maxx=-0x3f3f3f3f;
for(int i=0;i<x.size();i++)
if(x[i]<minn)
minn=x[i],min_pos=i;
for(int i=0;i<x.size();i++)
if(x[i]>maxx)
maxx=x[i],max_pos=i;
// printf("max_pos=%d min_pos=%d\n",max_pos,min_pos);
if(x[min_pos]+x[max_pos]>m)
{
vector<int>cur1,cur2;
cur1.clear(),cur2.clear();
for(int i=0;i<max_pos;i++) cur1.push_back(x[i]);
for(int i=max_pos+1;i<x.size();i++) cur2.push_back(x[i]);
int cur_ans1=solve(cur1);
int cur_ans2=solve(cur2);
return 1ll*cur_ans1*cur_ans2%mod;
}
vector<int>cur;
cur.clear();
for(int i=0;i<min_pos;i++) cur.push_back(x[i]);
for(int i=min_pos+1;i<x.size();i++) cur.push_back(x[i]);
return 1ll*solve(cur)*x.size()%mod;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d",&a[i]),vec.push_back(a[i]);
if(n==1) {printf("1\n");return 0;}
printf("%d\n",solve(vec));
return 0;
}
T2 stat
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 75
#define mod 1000000007
using namespace std;
int n,k;
int a[MAXN],b[MAXN];
inline void print(int *x)
{
for(int i=1;i<=n;i++) printf("%d ",x[i]);
puts("");
}
namespace subtask1
{
inline void solve()
{
int ans=0;
for(int i=1;i<=n;i++) a[i]=b[i]=i;
do
{
do
{
int cur_ans=0;
for(int i=1;i<=n;i++) cur_ans+=max(a[i],b[i]);
if(cur_ans>=k) ans++;
}while(next_permutation(&b[1],&b[n+1]));
}while(next_permutation(&a[1],&a[n+1]));
printf("%d\n",ans);
}
}
namespace subtask2
{
long long ans=0;
int tmp[MAXN],done[MAXN];
inline void search(int x)
{
if(x>n)
{
long long sum=0;
for(int i=1;i<=n;i++) sum+=max(tmp[i],i);
if(sum>=k) ans++;
return;
}
for(int i=1;i<=n;i++)
{
if(done[i]) continue;
tmp[x]=i,done[i]=1;
search(x+1);
tmp[x]=0,done[i]=0;
}
}
inline void solve()
{
for(int i=1;i<=n;i++) done[i]=0;
search(1);
for(int i=1;i<=n;i++)
ans=1ll*ans*i%mod;
printf("%lld\n",ans);
}
}
namespace subtask3
{
long long ans;
long long f[80][80][5010];
inline void solve()
{
f[0][0][0]=1;
for(int i=1;i<=n;++i)
for(int j=0;j<i;++j)
for(int k=0;k<=4901;++k)
if(f[i-1][j][k])
{
f[i][j+1][k+i]=(f[i][j+1][k+i]+f[i-1][j][k])%mod;
f[i][j+2][k+2*i]=(f[i][j+2][k+2*i]+f[i-1][j][k]*(i-1-j)*(i-1-j))%mod;
f[i][j+1][k+i]=(f[i][j+1][k+i]+2*f[i-1][j][k]*(i-1-j))%mod;
f[i][j][k]=(f[i][j][k]+f[i-1][j][k])%mod;
}
for(int i=k;i<=4901;++i)
ans=(ans+f[n][n][i])%mod;
for(int i=1;i<=n;++i)
ans=(ans*i)%mod;
printf("%lld",ans);
}
}
using namespace subtask1;
using namespace subtask2;
using namespace subtask3;
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce2.in","r",stdin);
#endif
scanf("%d%d",&n,&k);
if(n<=5) subtask1::solve();
else if(n<=10) subtask2::solve();
else subtask3::solve();
return 0;
}
T3 sequence
Day2
T1 baby
#include<algorithm>
#include<cstdio>
#include<cstring>
#define N 550000
#define M 100005
using namespace std;
int a[N][4],b[5]={-1,0,1,0,-1},d[M],e[M],f[M],g[M],h[M],i,j,l,m,n,o[N<<2],p[N<<2],q,s[N<<3],t,z;char c[N];bool w[N][4];
inline void add(int u){while(u<=t<<1)s[u]++,u+=u&-u;}
inline void del(int u){while(u<=t<<1)s[u]--,u+=u&-u;}
inline bool cmp(int u,int v){return a[d[u]][f[u]]<a[d[v]][f[v]];}
void dfs(int u,int v)
{
++v%=4;
while(!w[u][v])(v+=3)%=4;
if(a[u][v]<=t)return;
a[u][v]=++t,o[t]=u,p[t]=v;
dfs(u+m*b[v]+b[v+1],v);
}
inline int sum(int u)
{
int v=0;
while(u)v+=s[u],u-=u&-u;
return v;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d%d%*s",&n,&m,&q),memset(a,0x7f,sizeof a);
for(i=1;i<=n;i++)
{
for(scanf("%s",c),j=1;j<m;j++)if(c[j<<1]=='.')w[(i-1)*m+j][1]=w[(i-1)*m+j+1][3]=true;
for(scanf("%s",c+1),j=1;j<=m;j++)if(c[j<<1]=='.')w[(i-1)*m+j][2]=w[i*m+j][0]=true;
}
for(i=0;i<q;i++)
{
int x,y;
scanf("%d%d",&x,&y),d[i]=(x-1)*m+y;
scanf("%d%d",&x,&y),e[i]=(x-1)*m+y;
scanf("%s",c),g[i]=i;
if(*c=='U')f[i]=0;
else if(*c=='R')f[i]=1;
else if(*c=='D')f[i]=2;
else if(*c=='L')f[i]=3;
while(!w[d[i]][f[i]])(f[i]+=3)%=4;
}
for(dfs(1,0),i=1;i<=n*m;i++)add(min(min(a[i][0],a[i][1]),min(a[i][2],a[i][3])));
for(sort(g,g+q,cmp),i=1,j=0;j<q;)
{
while(i<=t&&a[d[g[j]]][f[g[j]]]>i)
del(i),a[o[i]][p[i]]+=t,add(min(min(a[o[i]][0],a[o[i]][1]),min(a[o[i]][2],a[o[i]][3]))),i++;
while(j<q&&a[d[g[j]]][f[g[j]]]==i)
h[g[j]]=sum(min(min(a[e[g[j]]][0],a[e[g[j]]][1]),min(a[e[g[j]]][2],a[e[g[j]]][3]))),j++;
}
for(i=0;i<q;i++)printf("%d\n",h[i]);
return 0;
}
T2 Bike
T3 Boom
Day3
T1 sequence
神仙乱搞qwq
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define MAXN 100010
using namespace std;
int n,m,q,tot,K,base,mod;
int a[MAXN],rt[MAXN];
bool done[MAXN];
struct Node{int v,ls,rs;}t[MAXN<<5];
struct Node2{int r_pos,hash;};
vector<int>pos[MAXN];//pos[a]表示a值的位置
inline void insert(int &x,int f,int l,int r,int k)
{
x=++tot;
t[x]=t[f],t[x].v++;
if(l==r) return;
int mid=(l+r)>>1;
if(k<=mid) insert(t[x].ls,t[f].ls,l,mid,k);
else insert(t[x].rs,t[f].rs,mid+1,r,k);
}
inline int query(int x,int l,int r,int k)
{
if(k>t[x].v||k==0) return -1;
if(l==r) return l;
int mid=(l+r)>>1;
if(k<=t[t[x].ls].v) return query(t[x].ls,l,mid,k);
else return query(t[x].rs,mid+1,r,k-t[t[x].ls].v);
}
inline void solve(vector<Node2>&x)
{
for(int now=1;now<=n;now++)
{
vector<Node2>nxt;
int minn=query(rt[x[0].r_pos+1],1,MAXN-10,now);
// cout<<"minn="<<minn<<endl;
if(minn==-1) return;
int st=0;
for(st=pos[minn].size()-1;st>=0;st--)
{if(pos[minn][st]<=x[0].r_pos) break;}
// cout<<"st="<<st<<endl;
if(st+1==(int)pos[minn].size()) continue;
for(int i=st+1;i<pos[minn].size();i++)//枚举之后能接哪些位置
{
for(int j=0;j<x.size()&&x[j].r_pos<pos[minn][i];j++)//枚举前面从哪个位置来接新数
{
int hash=(1ll*x[j].hash*base+minn)%mod;
printf("%d\n",hash);
// printf("K=%d\n",K);
K--;
if(K<=0) return;
nxt.push_back((Node2){pos[minn][i],hash});
}
if(K<=0) return;
}
// for(int i=0;i<nxt.size();i++) cout<<nxt[i].r_pos<<" "; cout<<endl;
solve(nxt);
if(K<=0) return;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d%d%d",&n,&K,&base,&mod);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),pos[a[i]].push_back(i);
for(int i=n;i>=0;i--)
{
if(done[a[i]]==0)
done[a[i]]=1,insert(rt[i],rt[i+1],1,MAXN-10,a[i]);
else rt[i]=rt[i+1];
}
// for(int i=1;i<=n;i++) printf("rt[%d]=%d\n",i,rt[i]);
vector<Node2>cur;
cur.push_back((Node2){0,0});
solve(cur);
return 0;
}
T2 game
这份代码是用emacs写的......所以缩进锅了qwqwq
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<vector>
#define MAXN 300010
#define mod 1000000007
using namespace std;
int n,A,B,ans1,ans2,t;
int ans[MAXN],ffa[MAXN],b[MAXN],g[MAXN],c[MAXN];
int head[MAXN],dis[MAXN],fa[MAXN],pref[MAXN],suf[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
inline bool cmp(int x,int y){return ans[x]>ans[y];}
inline void add(int from,int to)
{
edge[++t].nxt=head[from],edge[t].to=to;
head[from]=t;
}
inline void dfs1(int x,int pre,int ban)
{
ans[x]=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre||v==ban) continue;
dfs1(v,x,ban);
}
int cur=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre||v==ban) continue;
b[++cur]=v;
}
sort(&b[1],&b[cur+1],cmp);
for(int i=1;i<=cur;i++) ans[x]=max(ans[x],ans[b[i]]+i);
}
inline void dfs2(int x,int pre)
{
int t=0;
if(pre) ans[0]=g[x],b[++t]=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
b[++t]=v;
}
sort(&b[1],&b[t+1],cmp);
pref[0]=suf[t+1]=0;
for(int i=1;i<=t;i++) pref[i]=max(pref[i-1],ans[b[i]]+i);
ans1=min(ans1,pref[t]);
for(int i=t;i;i--) suf[i]=max(suf[i+1],ans[b[i]]+i-1);
for(int i=1;i<=t;i++)
if(b[i])
g[b[i]]=max(pref[i-1],suf[i+1]);
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v!=pre)
dfs2(v,x);
}
}
inline void dfs3(int x,int pre)
{
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
ffa[v]=x;
dfs3(v,x);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d%d",&n,&A,&B);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs1(1,0,0);
ans1=n-1;
dfs2(1,0);
printf("%d\n",ans1);
dfs3(A,0);
int now=B,top=0;
while(now) c[++top]=now,now=ffa[now];
int l=1,r=top-1;
ans2=n-1;
while(l<=r)
{
int mid=(l+r)>>1;
dfs1(A,0,c[mid]);
dfs1(B,0,c[mid+1]);
ans2=min(ans2,max(ans[A],ans[B]));
if(ans[A]>ans[B]) l=mid+1;
else r=mid-1;
}
printf("%d\n",ans2);
return 0;
}
T3 tree
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 100010
#define mod 1000000007
using namespace std;
int n,m;
int f[MAXN][11],fa[MAXN],st[MAXN];
inline int fpow(int x,int y)
{
int cur_ans=1;
while(y)
{
if(y&1) cur_ans=1ll*cur_ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return cur_ans;
}
inline void dp(int x,int y)
{
for(int i=10;i;i--)
for(int j=1;j<i;j++)
f[x][i]=(f[x][i]+1ll*f[x][j]*f[y][i-j]%mod)%mod;
}
inline void dp2(int x,int y)
{
for(int i=1;i<=10;i++)
for(int j=1;j<i;j++)
f[x][i]=(f[x][i]-1ll*f[x][j]*f[y][i-j]%mod)%mod;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
freopen("ce.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&f[i][1]);
for(int i=2;i<=n;i++) scanf("%d",&fa[i]);
for(int i=n;i>1;i--) dp(fa[i],i);
for(int p=1;p<=m;p++)
{
int op,k,s,t,top;
scanf("%d%d%d",&op,&k,&s);
if(op==1)
{
for(int i=1;i<=10;i++) f[0][i]=0;
for(t=k,top=0;t&&top<10;t=fa[t]) st[++top]=t;
while(t=st[top--])
{
for(int i=1;i<=10;i++)
f[n+1][i]=f[0][i],f[0][i]=f[t][i];
dp(0,n+1);
if(top) dp2(0,st[top]);
}
printf("%d\n",(f[0][s]+mod)%mod);
}
else
{
for(t=k,top=0;t&&top<10;t=fa[t]) st[++top]=t;
for(int i=top-1;i;i--) dp2(st[i+1],st[i]);
int cur_ans=1ll*fpow(f[k][1],mod-2)*s%mod;
for(int i=1;i<=10;i++)
f[k][i]=1ll*f[k][i]*cur_ans%mod;
for(int i=1;i<top;i++)
dp(st[i+1],st[i]);
}
}
return 0;
}
Day4
T1 tree
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 3010
using namespace std;
int n,q,k,t,ans=0x3f3f3f3f;
int dp[MAXN][MAXN][3],siz[MAXN],head[MAXN];
struct Edge{int nxt,to,dis;}edge[MAXN<<1];
inline void add(int from,int to,int dis)
{
edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis;
head[from]=t;
}
inline void solve(int x,int pre)
{
siz[x]=1;
dp[x][1][0]=dp[x][1][1]=dp[x][1][2]=0;
dp[x][0][0]=dp[x][0][1]=dp[x][0][2]=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
solve(v,x);
// printf("x=%d v=%d\n",siz[x],siz[v]);
for(int j=min(k,siz[x]+siz[v]);j>=2;j--)
{
for(int j2=max(1,j-siz[x]);j2<=min(j,siz[v]);j2++)//v_size
{
int j1=j-j2;//x_size
// cout<<j2<<" "<<j2<<endl;
dp[x][j][0]=min(dp[x][j][0],dp[x][j1][0]+dp[v][j2][0]+edge[i].dis*2);
dp[x][j][1]=min(dp[x][j][1],dp[x][j1][0]+dp[v][j2][1]+edge[i].dis);
dp[x][j][1]=min(dp[x][j][1],dp[x][j1][1]+dp[v][j2][0]+edge[i].dis*2);
dp[x][j][2]=min(dp[x][j][2],dp[x][j1][1]+dp[v][j2][1]+edge[i].dis);
dp[x][j][2]=min(dp[x][j][2],dp[x][j1][2]+dp[v][j2][0]+edge[i].dis*2);
dp[x][j][2]=min(dp[x][j][2],dp[x][j1][0]+dp[v][j2][2]+edge[i].dis*2);
}
}
siz[x]+=siz[v];
}
ans=min(ans,dp[x][k][2]);
// printf("x=%d %d\n",x,ans);
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d",&n,&k);
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
memset(dp,0x3f,sizeof(dp));
solve(1,0);
printf("%d\n",ans);
return 0;
}
T2
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define MAXN 10000000
#define mod 998244353
using namespace std;
int n,k,T;
int inv[MAXN+10],ff[MAXN+10],fn[MAXN+10],F[MAXN+10];
inline int fpow(int x,int y)
{
int cur_ans=1;
while(y)
{
if(y&1) cur_ans=1ll*cur_ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return cur_ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d%d%d",&n,&k,&T);
if(T==1)
{
printf("1\n");
return 0;
}
fn[0]=1;
for(int i=1;i<=MAXN;i++) fn[i]=1ll*fn[i-1]*i%mod;
inv[MAXN]=fpow(fn[MAXN],mod-2);
for(int i=MAXN-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
for(int i=1;i<=MAXN;i++) ff[i]=1ll*inv[i]*fn[i-1]%mod;
int cur_ans=1;
int cur=fpow(T-1,mod-2);
F[0]=1ll*T*(mod-cur)%mod*(1-fpow(T,n)+mod)%mod;
for(int i=1;i<=k;i++)
{
cur_ans=1ll*cur_ans*(n-i+1)%mod*ff[i]%mod;
F[i]=(1ll*F[i-1]-1ll*T*cur_ans%mod+mod)%mod;
F[i]=1ll*F[i]*cur%mod;
}
cur_ans=fpow(cur_ans,mod-2);
printf("%lld\n",1ll*cur_ans*F[k-1]%mod);
return 0;
}
T3
这个题的快读板子感觉挺好qwqwq
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<algorithm>
#define MAXN 1000010
using namespace std;
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int qr;
// getchar
#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
// print the remaining part
inline void flush () {
fwrite (obuf, 1, oS - obuf, stdout);
oS = obuf;
}
// putchar
inline void putc (char x) {
*oS ++ = x;
if (oS == oT) flush ();
}
// input a integer
template <class I>
inline void gi (I &x) {
for (c = gc(); c < '0' || c > '9'; c = gc());
for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
}
// print a integer
template <class I>
inline void print (I &x) {
if (!x) putc ('0');
while (x) qu[++ qr] = x % 10 + '0', x /= 10;
while (qr) putc (qu[qr --]);
}
}
using io :: gi;
using io :: putc;
using io :: print;
int n,Q;
int a[MAXN],p[MAXN],pos[MAXN],ans[MAXN],head[MAXN];
struct Node{int l,d,id,nxt;}q[MAXN];
inline void insert(int &x,int k)
{
for(int i=30;i>=0;i--)
{
if(x&(1<<i))
{
if(!p[i]) {p[i]=x,pos[i]=k;return;}
if(k>pos[i]) swap(k,pos[i]),swap(p[i],x);
x^=p[i];
}
}
}
inline int query(int cur_ans,int l)
{
for(int i=30;i>=0;i--)
if(l<=pos[i]&&(cur_ans^p[i])>cur_ans)
cur_ans=cur_ans^p[i];
return cur_ans;
}
int main()
{
gi(n);
for(int i=1;i<=n;i++) gi(a[i]);
gi(Q);
for(int i=1;i<=Q;++i)
{
int l,r,d;
gi(l),gi(r),gi(d);
q[i]=(Node){l,d,i,head[r]};
head[r]=i;
}
for(int i=1;i<=n;++i)
{
insert(a[i],i);
// for(int i=0;i<=10;i++) printf("p[%d]=%d\n",i,p[i]);
for(int j=head[i];j;j=q[j].nxt)
ans[q[j].id]=query(q[j].d,q[j].l);
}
for(int i=1;i<=Q;++i) print(ans[i]),putc('\n');
io::flush();
return 0;
}
Day5
T1 tree
T2 permutation
有限制位置的错排问题。
- 10pts 枚举排列,然后判断是否是对的。时间复杂度\(O(n!n)\)
- 100pts 我们考虑容斥。
我们把已经看到值的位置直接忽略,之后就不放这个位置了,如果没有错排的限制,显然结果是\((n-k)!\)的。
但是这样有一部分是错的对吧,错的就是比如1放到了1这种情况,我们去掉这种一个数放错的情况,就是减去\(C_{m}^1(n-k-1)!\)
但是这样子就减多了,比如说1,2放到了1,2这种两个数放错的情况,所以要加上\(C_{m}^2(n-k-2)!\)
.......然后以此类推,就是答案了.
其中注意一下,如果这个数开始已经被放过了,那么我们也不需要管它.
所以m的数量是自己原先既没有摆放位置,它对应的位置也没有数的个数.
(考场忘了最后(ans+mod)%mod)了,炸成了40.......
AC代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define MAXN 1000010
#define mod 998244353
using namespace std;
int n;
int p[MAXN];
namespace subtask1 //10pts
{
int ans,cnt;
int done[MAXN],cur[MAXN];
inline void search(int x)
{
if(x>n)
{
// for(int i=1;i<=n;i++) printf("%d ",cur[i]); puts("");
ans++;
return;
}
if(p[x]){cur[++cnt]=p[x];search(x+1);cnt--;return;}
for(int i=1;i<=n;i++)
{
if(done[i]||i==x) continue;
done[i]=1;cur[++cnt]=i;
search(x+1);
done[i]=0;cnt--;
}
}
inline void solve()
{
for(int i=1;i<=n;i++) if(p[i]) done[p[i]]=1;
search(1);
printf("%d\n",ans);
}
}
namespace subtask2
{
int fn[MAXN],inv[MAXN],f[MAXN],done[MAXN];
inline int fpow(int x,int y)
{
int cur_ans=1;
while(y)
{
if(y&1) cur_ans=1ll*cur_ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return cur_ans;
}
inline void init()
{
fn[0]=1;
for(int i=1;i<=MAXN-10;i++) fn[i]=1ll*fn[i-1]*i%mod;
inv[MAXN-10]=fpow(fn[MAXN-10],mod-2);
for(int i=MAXN-10-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
// for(int i=0;i<5;i++) printf("fn[%d]=%d\n",i,fn[i]);
// for(int i=0;i<5;i++) printf("inv[%d]=%d\n",i,inv[i]);
}
inline int C(int x,int y)
{
if(y==0||x==y) return 1;
if(y>x) return 0;
return 1ll*fn[x]*inv[y]%mod*inv[x-y]%mod;
}
inline void solve()
{
init();
int m=0,ans=0,g=1,k=0;
for(int i=1;i<=n;i++)
{
if(p[i])
k++,done[p[i]]=1;
}
for(int i=1;i<=n;i++)
if(done[i]==0&&p[i]==0) m++;
for(int i=0;i<=m;i++)
{
// cout<<fn[n-k-1]<<" "<<C(m,i)<<endl;
ans=(ans+1ll*g*fn[n-k-i]%mod*C(m,i))%mod;
g*=-1;
// printf("i=%d ans=%d\n",i,ans);
}
printf("%d\n",(ans+mod)%mod);
}
}
using namespace subtask1;
using namespace subtask2;
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
if(n<=10) subtask1::solve();
else subtask2::solve();
return 0;
}
T3 color
- 20pts 暴力枚举每条边的状态,然后判断即可。时间复杂度\(O(n^2 2^n)\)
- 40(=20+20)pts 一条链的状态,显然每个点的答案等于\(i*(n-i+1)\)
- 60(=20+40)pts 我们设\(dp[i]\)表示以i为根的子树的答案,那么我们枚举一下每个点作为根,就能算出来答案了。时间复杂度\(O(n^2)\)
- 100pts 我们加上换根DP即可把枚举根的那个n优化掉。(但是注意去除影响的时候不能直接除逆元,因为这道题累加答案的操作是乘法,如果乘上了一个0的逆元就GG了--->会挂成70分)时间复杂度\(O(n)\)
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define MAXN 100010
#define mod 1000000007
using namespace std;
int n,t;
int fa[MAXN],dp[MAXN],head[MAXN];
int up[MAXN],pref[MAXN],suf[MAXN],b[MAXN];
struct Edge{int nxt,to;}edge[MAXN<<1];
vector<int>e[MAXN];
inline void add(int from,int to)
{
edge[++t].nxt=head[from],edge[t].to=to;
head[from]=t;
}
inline int fpow(int x,int y)
{
int cur_ans=1;
while(y)
{
if(y&1) cur_ans=1ll*cur_ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return cur_ans;
}
inline void init(int x,int pre)
{
dp[x]=1;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
init(v,x);
dp[x]=1ll*dp[x]*(dp[v]+1)%mod;
// dp[x]=(dp[x]+1ll*dp[x]*(dp[v]+1))%mod;
}
}
inline void change_root(int x,int pre)
{
dp[x]=1ll*dp[x]*(up[x]+1)%mod;
int cnt=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
b[++cnt]=dp[v];
}
pref[0]=(up[x]+1)%mod;
suf[cnt+1]=1;
for(int i=1;i<=cnt;i++) pref[i]=1ll*pref[i-1]*(b[i]+1)%mod;
for(int i=cnt;i>=1;i--) suf[i]=1ll*suf[i+1]*(b[i]+1)%mod;
cnt=0;
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
cnt++;
up[v]=1ll*pref[cnt-1]*suf[cnt+1]%mod;
}
for(int i=head[x];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(v==pre) continue;
change_root(v,x);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("ce.in","r",stdin);
#endif
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
scanf("%d",&fa[i]);
add(fa[i],i),add(i,fa[i]);
e[fa[i]].push_back(i);
e[i].push_back(fa[i]);
}
init(1,0);
// for(int i=1;i<=n;i++) up[i]=1;
change_root(1,0);
for(int i=1;i<=n;i++) printf("%d ",dp[i]);
return 0;
}