2017.10.16离线赛总结
2017-10-16 21:16
169 查看
draw ——3787
思路:这是源自一个岛国的游戏…思考一下画鬼脚的本质,一条竖线其实就是一次对相邻两个元素的交换操作。
所以,模拟画鬼脚的时候,只需要按照高度从高到低,依次进行所有的交换操作即可。
那么,对于第二问,众所周知,就是求排列的逆序对数——线段树或BIT
#include<bits/stdc++.h> #define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++) #define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--) #define INF 0x3f3f3f3f #define LL long long #define N 100005 #define M 1000005 #define INF 0x3f3f3f3f using namespace std; int n,m,ans; int pos ; struct BIT{ int A ; void add(int x,int v){ while(x<=N){ A[x]+=v; x+=x&-x; } } int query(int x){ int res=0; while(x){ res+=A[x]; x-=x&-x; } return res; } }BIT; int main(){ scanf("%d%d",&n,&m); REP(i,1,n)pos[i]=i; REP(i,1,m){ int x;scanf("%d",&x); swap(pos[x],pos[x+1]); } REP(i,1,n)printf("%d ",pos[i]); DREP(i,n,1){ ans+=BIT.query(pos[i]); BIT.add(pos[i],1); } printf("\n%d\n",ans); return 0; }
run ——3788
思路:50%:直接模拟,链时,显然 他会消灭所有距离他为偶数条的祖先。100%:先dfs,遇到一个点就把这个点记录到一个数组,即求出了树的欧拉序,显然如果不考虑循环的话,guard是在这个序列上每次往后走一个,起始位置就是第i个点第一次出现的位置。而显然 YOUSIKI 只可能与他的所有祖先相遇,所以我们要最短路把树上的这些祖先的位置标记出来。
假设 YOUSIKI 现在走到了 x 点,过了 t 秒,那么我们在这个序列上遍历 x 出现的所有位置,并查看这个位置往前 t 个是否为 x 的祖先,如果是,把那个祖先标为1,表示已被消灭。
复杂度 O(n)。
#include<bits/stdc++.h> #define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++) #define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--) #define INF 0x3f3f3f3f #define LL long long #define N 500005 #define INF 0x3f3f3f3f using namespace std; int n,m; void Rd(int &ans){ ans=0;char c; while((c=getchar())<48); do ans=(ans<<1)+(ans<<3)+(c^48); while((c=getchar())>47); } struct P100{ int n,T,ans; int fa ,Lt[N<<1], mark[N<<1]; vector<int>E ,es ; void Init(){ memset(fa,0,sizeof(fa)); memset( mark,0,sizeof( mark)); memset(Lt,0,sizeof(Lt)); REP(i,1,n)E[i].clear(),es[i].clear(); T=0;ans=0; } void dfs(int x,int f){ Lt[x]=++T; fa[x]=f; es[x].push_back(T); REP(i,0,E[x].size()-1){ int y=E[x][i]; dfs(y,x); es[x].push_back(++T); } } void solve(){ Init(); Rd(n); REP(i,1,n){ int k,x; Rd(k); REP(j,1,k)Rd(x),E[i].push_back(x); } int beg;Rd(beg); dfs(1,0); for(int i=beg;i;i=fa[i])mark[Lt[i]]=1; int t=0; for(int i=beg;i;i=fa[i]){ REP(j,0,es[i].size()-1){ int dt=es[i][j]-t; if(dt<=0 || ! mark[dt])continue; ans++,mark[dt]=0; } t++; } printf("%d\n",ans); } }AC; int main(){ int Case; Rd(Case); while(Case--)AC.solve(); return 0; }
tri ——3789
思路:5%:直接输出2^n-1;
20%:强模拟;
40%:推出等式,与组合有关——∑C(i,x)(i=0 to n-1) = C(n,x+1)
m=1时:可以推出通项公式——2^(n-1)*n;
m=2时:也可以推出——n*(2^(n-1)+2^(n-2)*(n-1));
所以可以把问题转换到第 n+1 行上,相当于求 ∑C(n,i)*i^m (i=1 to n) ,O(n lg m);
95%:
考虑这个式子的组合意义
相当于先枚举 i,然后在 n 个颜色里选出 i 个颜色,再用这 i 个颜色可重复排出一个长度为m 的排列的方案数。
换个思路。
枚举最后排列中实际用了几种颜色(*C(n,i) ),其他的颜色可以选或不选( *2^(n-i)),然后再乘上 i 种颜色能排出的排列数。
现在问题在于排列数怎么求,这里可以用 dp 或容斥,说一下容斥。
首先 i 个颜色随便放的方案数是 i^m,但现在可能最终只出现了 i-1 种颜色,所以需要减去C(i,i − 1) ∗ (i − 1)^m,同理再加上 C(i,i − 2) ∗ (i − 2)m…O(m^2)。
可能有人已经发现这个东西就是 S(m,i) ∗ i!,S为第二类斯特林数,表示把 m 个物品放入 i个相同盒子且盒子非空的方案数,因为本题是一个排列,所以需要乘上i! 。
第二类斯特林数可以用 或容斥求,O(n^2) 。
将容斥的式子化简一下,发现是一个卷积的形式,用 NTT 可以求出 S(m, 1) 到S(m, m) , O(mlogm + mlogn),然而这5分太恶心了,有 AK 梦想的选手
可以写一写。
#include<bits/stdc++.h> #define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++) #define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--) #define INF 0x3f3f3f3f #define LL long long #define N 1000005 #define Mod 998244353 #define INF 0x3f3f3f3f // LL mod using namespace std; LL n,m; LL dp[3005][3005]; void Init(){ dp[0][0]=1; REP(i,1,n) REP(j,1,i) dp[i][j]=(dp[i-1][j]+dp[i-1][j-1])%Mod; } LL Pow(LL a,LL b){ LL res=1; while(b>0){ if(b&1)res*=a,res%=Mod; b>>=1,a*=a,a%=Mod; } return res; } struct p20{ LL ans; void solve(){ Init(); REP(j,1,n){ LL p=Pow(j,m); REP(i,j,n)dp[i][j]*=p,dp[i][j]%=Mod,ans+=dp[i][j],ans%=Mod; } printf("%lld\n",ans); } }p20; struct p40{ void solve(){ LL C=n; LL ans=n; REP(i,1,n){ C=(C*(n-i)%Mod)*Pow(i+1,Mod-2)%Mod; ans+=C*Pow(i+1,m)%Mod,ans%=Mod; } printf("%lld\n",ans); } }p40; struct p95{ LL fac[3005]; void Init(){ dp[0][0]=1; REP(i,1,3005){ dp[i][0]=1; REP(j,1,i)dp[i][j]=(dp[i-1][j-1]+dp[i-1][j])%Mod; } fac[0]=fac[1]=1;// i! REP(i,2,3005)fac[i]=(i*fac[i-1])%Mod; } void solve(){ Init(); LL ans=0,p=n; REP(i,1,m){ LL f=-1,sum=Pow(i,m); DREP(j,i-1,0)sum+=f*dp[i][j]*Pow(j,m)%Mod,sum%=Mod,f=-f;//rong chi ans+=p*Pow(2,n-i)%Mod*sum%Mod,ans%=Mod; p=p*(n-i)%Mod*Pow(i+1,Mod-2)%Mod; } printf("%lld\n",ans%Mod); } }p95; int main(){ // freopen("tri.in","r",stdin); // freopen("tri.out","w",stdout); scanf("%lld%lld",&n,&m); if(!m)printf("%lld\n",Pow(2,n)-1); else if(m==1)printf("%lld\n",((Pow(2,n-1)%Mod)*n)%Mod); else if(m==2)printf("%lld\n",((Pow(2,n-1)%Mod+((Pow(2,n-2)%Mod)*(n-1))%Mod)*n)%Mod); else if(n<=2000)p20.solve(); else if(n<=1000000)p40.solve(); else if(m<=3000)p95.solve(); return 0; }
小结:今天的题着实有点骚,但有新意,还是可以,只是今天第3题的暴力都没打…第2题写着写着就内心崩溃了…看到第3题(woc,第3题数论题,数论是什么…)。
相关文章推荐
- 经验分享:迅雷离线下载无线端设计总结
- 20170723离线赛比赛总结
- 完整的ubuntu镜像源/本地源/更新源/离线升级包!制作总结!
- 离线安装chrome插件Postman总结
- CDH5 Hadoop集群完全离线安装步骤总结
- Hybrid APP的离线存储总结
- 2017-9-29离线赛总结
- Xmpp问题总结:XMPP离线管理
- Vim常见指令与问题总结(五)---windowns下vim离线安装插件及介绍
- 2017/7/29 离线赛 总结
- Tensorflow 离线安装跳坑总结
- 2017.10.30离线赛总结
- 20171009离线赛总结
- 2017-10-9离线赛总结
- 17.7.26离线赛比赛总结
- 离线赛20171017总结
- 2017-10-19离线赛总结
- PAIP.paip.手机离线ROOT过程总结
- 2017-9-28离线赛总结
- 2017.10.27离线赛总结