CF453(Div1 简单题解)
A .Little Pony and Expected Maximum
pro:给定M,N,表示一个M面的骰子,甩N次,问出现的最大的数的期望。
sol:容斥,f(i)表示最大数<=i的期望,那么最大数=x的期望就是f(x)-f(x-1);
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=200010; double dp[maxn]; double qpow(double a,int x) { double res=1.0;while(x){ if(x&1) res=res*a; a=a*a; x>>=1; } return res; } int main() { int M,N; double ans=0.; scanf("%d%d",&M,&N); rep(i,1,M) dp[i]=qpow(1.0*i/M,N); rep(i,1,M) ans+=(dp[i]-dp[i-1])*i; printf("%.10lf\n",ans); return 0; }
B .Little Pony and Harmony Chest
pro:给定数组a[],求一个两两互质的b[],使得abs(a[]-b[])最小,输出一个方案。 N<=100,a[]<=30
sol:两两互质,表示之前出现的素因子不能出现,而我们发现>60不可能,因为差值会变很大。 所以我们记录<=60的素数,然后状压DP,记录一下来源,最后倒回去输出即可。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=110; const int maxm=132000; int a[maxn],p[maxn],vis[maxn],tot,cnt; int pre[maxn][maxm],now[maxn][maxm],dp[maxn][maxm],fac[maxn]; vector<int>G[maxm]; void dfs(int pos,int Now) { if(pos==0) return ; dfs(pos-1,pre[pos][Now]); printf("%d ",now[pos][Now]); } int main() { int N,M,ans=100000,P; memset(dp,0x3f,sizeof(dp)); dp[0][0]=0; rep(i,2,57) { if(!vis[i]){ p[tot++]=i; for(int j=i+i;j<=57;j+=i) vis[j]=1; } } rep(i,1,57){ rep(j,0,tot-1){ if(i%p[j]==0){ fac[i]|=(1<<j); } } } M=(1<<tot)-1; rep(i,0,M) rep(j,1,57) if(!(fac[j]&i)) G[i].push_back(j),cnt++; scanf("%d",&N); rep(i,1,N) scanf("%d",&a[i]); rep(i,1,N){ rep(j,0,M) { for(int k=0;k<G[j].size();k++){ int v=G[j][k]; if(dp[i][j|fac[v]]>dp[i-1][j]+abs(a[i]-v)){ dp[i][j|fac[v]]=dp[i-1][j]+abs(a[i]-v); pre[i][j|fac[v]]=j; now[i][j|fac[v]]=v; } } } } rep(i,0,M) if(dp[N][i]<ans) ans=dp[N][i],P=i; dfs(N,P); return 0; }
C .Little Pony and Summer Sun Celebration
pro:给定N点M边的无向图(不一定连通),然后给没给点限制一个0或1,表示经过点的奇偶,让你找一条路径,满足路径长度<=N*4,而且满足奇偶要求。
sol:我们DFS,如果儿子的奇偶性未满足,满足我们再走一遍(fa->son->fa)即可,发现一定可以构造好。。。然后就是要求的奇数的点一定要连通。
#include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=2000010; int Laxt[maxn],Next[maxn],To[maxn],d[maxn],cnt; int a[maxn],b[maxn],tot,vis[maxn],t[maxn],F=1; void add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void dfs(int u,int f) { vis[u]=1; t[u]^=1; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(v!=f&&!vis[v]){ tot++; a[tot]=u; b[tot]=v; dfs(v,u); tot++; a[tot]=v; b[tot]=u; t[u]^=1; if(d[v]!=t[v]){ tot++; a[tot]=u; b[tot]=v; t[v]^=1; tot++; a[tot]=v; b[tot]=u; t[u]^=1; } } } } int main() { int N,M,u,v,root=-1; scanf("%d%d",&N,&M); rep(i,1,M){ scanf("%d%d",&u,&v); add(u,v); add(v,u); } rep(i,1,N) scanf("%d",&d[i]); rep(i,1,N) if(d[i]==1) root=i; if(root==-1) return puts("0"),0;// root=1; dfs(root,0); rep(i,1,N) if(!vis[i]&&d[i]==1) F=0; if(!F) return puts("-1"),0; if(t[root]!=d[root]) tot--; printf("%d\n",tot+1); printf("%d ",root); rep(i,1,tot) printf("%d ",b[i]); return 0; }
D .Little Pony and Elements of Harmony
FWT,不会,占位。
E .Little Pony and Lord Tirek
题意:N个马,给定了开始的能量值s[],以及能力上限m[],以及单位时间的能力上升值r[]。Q次操作,每次给出[L,R],吸走这个区间的马的能力和sum,求sum,马的能力被吸走后变为0。
思路:想不到线段树就可以做。。。。tql ,注意r可能为0,不要除0,免得RE。
主要一点就是,区间更新,区间时间一样了,我们就可以均摊复杂度了,即tag相同的区间利用预处理,不同的继续下推。
我们先预处理,把每个节点按照达到上限的时间排序,然后得到前缀和,用前缀和来快速得到,这个区间给定时间差后的sum。
时间复杂度O(N(logN)^2),空间O(NlogN);
#include<bits/stdc++.h> #define ll long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=100010; const int inf=2e9; int s[maxn],m[maxn],r[maxn],t[maxn],vis[maxn<<2]; int T[19][maxn]; ll pre[19][maxn],v[20][maxn]; struct in{ int m,r,t; in(){} in(int mm,int rr,int tt):m(mm),r(rr),t(tt){} bool friend operator<(in w,in v){ return w.t<v.t; } }fcy[maxn]; void build(int dep,int Now,int L,int R) { rep(i,L,R) fcy[i]=in(m[i],r[i],t[i]); sort(fcy+L,fcy+R+1); rep(i,L,R){ T[dep][i]=fcy[i].t; pre[dep][i]=fcy[i].m; v[dep][i]=fcy[i].r; if(i>L){ pre[dep][i]+=pre[dep][i-1];//满的部分前缀和 v[dep][i]+=v[dep][i-1]; //速度前缀和 } } if(L==R){ vis[Now]=0; return; } vis[Now]=-1; int Mid=(L+R)>>1; build(dep+1,Now<<1,L,Mid); build(dep+1,Now<<1|1,Mid+1,R); } ll query(int dep,int Now,int L,int R,int ql,int qr,int times) { if(vis[Now]==0){ vis[Now]=times; if(s[L]+1LL*times*r[L]>=m[L]) return 1LL*m[L]; return 1LL*s[L]+times*r[L]; } if(ql<=L&&qr>=R&&vis[Now]>0){ int p=upper_bound(T[dep]+L,T[dep]+R+1,times-vis[Now])-T[dep]; p--; ll res=((p>=L)?pre[dep][p]:0); //满的 res+=(v[dep][R]-((p>=L)?v[dep][p]:0))*(times-vis[Now]); //未满 vis[Now]=times; return res; } if(vis[Now]>=0) vis[Now<<1]=vis[Now<<1|1]=vis[Now]; int Mid=(L+R)>>1; ll res=0; if(ql<=Mid) res+=query(dep+1,Now<<1,L,Mid,ql,qr,times); if(qr>Mid) res+=query(dep+1,Now<<1|1,Mid+1,R,ql,qr,times); if(vis[Now<<1]==vis[Now<<1|1]) vis[Now]=vis[Now<<1]; else vis[Now]=-1; return res; } int main() { int N,M,ts,L,R; scanf("%d",&N); rep(i,1,N){ scanf("%d%d%d",&s[i],&m[i],&r[i]); if(!r[i]) t[i]=inf; else t[i]=m[i]/r[i]+(m[i]%r[i]?1:0); } build(1,1,1,N); scanf("%d",&M); rep(i,1,M){ scanf("%d%d%d",&ts,&L,&R); ll ans=query(1,1,1,N,L,R,ts); printf("%lld\n",ans); } return 0; }
It is your time to fight!