11.2 正睿停課訓練 Day15
目錄
2018.11.2 正睿停課訓練 Day15
時間:3.5h
期望得分:100+20+20
實際得分:100+20+0
A 鬱悶的小G(二分)
//二分。 #include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar() typedef long long LL; inline LL read() { LL now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } inline bool Check(LL x,LL a,LL b,LL c,LL d,LL e) { if(a<x) b-=x-a; if(e<x) d-=x-e; if(b<0||d<0) return 0; LL tmp=b+d; if(c<x) c+=tmp; return c>=x; } int main() { LL a=read(),b=read(),c=read(),d=read(),e=read(); LL l=0,r=2e18,mid,ans=0; while(l<=r) if(Check(mid=l+r>>1,a,b,c,d,e)) ans=mid,l=mid+1; else r=mid-1; printf("%lld\n",ans); return 0; }/* 2 2 1 2 2 100 100 100 0 0 */
B 小G的樹(樹形DP)
求樹的直徑需要用到子樹最長鏈與子樹內的最大直徑,都存下來就好了。
\(f[i][j][k]\)表示當前為點\(i\),\(i\)子樹最長鏈長度為\(j\),\(i\)子樹內最大直徑為\(k\),的概率(直徑不一定過點\(i\))。
轉移\(O(n^4)\)就行了。
概率\(\frac 12\)可以最後乘,也就是兩種可能的概率都算做\(1\)。同時存的數不會超過\(2^{60}\),所以可以用longlong。
最後乘\(\frac{1}{2^{n-1}}\),因為每條邊的概率都乘了\(2\)。
//0ms 1080kb #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> #define gc() getchar() typedef long long LL; const int N=62; int Enum,H[N],nxt[N<<1],to[N<<1],D[N]; LL f[N][N<<1][N<<1]; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } inline void AE(int u,int v) { to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum; to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum; } void Merge(int x,int v,int d1,int d2,int d3,int d4) { static LL g[N<<1][N<<1]; LL (*fx)[N<<1]=f[x],(*fv)[N<<1]=f[v]; LL tmp,tmp2; for(int a=0; a<=d1; ++a) for(int b=a; b<=d2; ++b) if((tmp=fx[a][b])) for(int c=0; c<=d3; ++c) for(int d=c; d<=d4; ++d) { if(!fv[c][d]) continue; tmp2=tmp*fv[c][d]; g[std::max(a,c+1)][std::max(std::max(b,d),a+c+1)]+=tmp2, g[std::max(a,c+2)][std::max(std::max(b,d),a+c+2)]+=tmp2; } int l1=std::max(d1,d3+2),l2=std::max(std::max(d2,d4),d1+d3+2); for(int i=0; i<=l1; ++i) for(int j=i; j<=l2; ++j) fx[i][j]=g[i][j], g[i][j]=0; } int DFS(int x,int fa) { int mxd=0,dia=0; f[x][0][0]=1; for(int i=H[x],v,d; i; i=nxt[i]) if((v=to[i])!=fa) { d=DFS(v,x), Merge(x,v,mxd,dia,d,D[v]); dia=std::max(dia,std::max(D[v],mxd+d)), mxd=std::max(mxd,d); } return D[x]=dia, mxd+2; } int main() { int n=read(); for(int i=1; i<n; ++i) AE(read(),read()); int d=DFS(1,1); double ans=0; for(int i=0; i<=d; ++i) for(int j=i; j<=D[1]; ++j) ans+=1.0*f[1][i][j]*j; printf("%.10lf\n",ans/(1ll<<n-1)); return 0; }
C 數的距離(思路)
原題:HDU5812。
對於\(dis(x,y)\),把\(x,y\)質因數分解後(令\(x=\prod_{i=1}^k p_i^{a_i},y=\prod_{i=1}^k p_i^{b_i}\)),則\(dis(x,y)=\sum_{i=1}^k |a_i-b_i|\)。
實際上我們可以去掉\(x,y\)公共的部分,即令\(f(x)=x的質因子個數\),則\(dis(x,y)=f(\frac{x}{\gcd(x,y)})+f(\frac{y}{\gcd(x,y)})\)。
\(f\)可以線性篩預處理,即\(f(\frac{x}{\gcd(x,y)})\)
不妨在插入\(y\)時,也列舉\(y\)的每個約數\(d\),然後更新\(g(d)=\min\{g(d),f(\frac yd)\}\)。\(g(d)\)表示\(f(\frac yd)(y在集合中)\)的最小值。
這樣就可以\(O(1)\)求\(\min\{f(\frac yd)\}\)了。
但是還有刪除操作,我們需要維護\(g(d)\)的最小值。
注意到\(f(x)\)不會超過\(20\),且我們只關心\(f(\frac yd)\)的大小,所以可以用\(cnt[d][t]\)表示\(g(d)\)中滿足\(g(d)=t\)的\(y\)的個數,用一個二進位制數\(s[d]\)表示\(g(d)\)中每個值的存在性。這樣就可以\(O(1)\)更新\(g(d)\),並在查詢時直接用位運算找到最小的\(g(d)\)。
(事實上用不到\(f\)陣列,因為只需要在列舉約數的時候算下個數就行了)
質因數種類是最多\(7\)個,但不代表就是\(2,3,5,7,11,13,17\)這些啊。。
可以處理出每個數的一個質因數\(p\),\(n\)每次直接除\(p[n]\),就不用列舉質數了。
另外看到這個就想到\(k\)維曼哈頓距離。。最大好像能做吧(就是複雜度有點大),求最小距離是不是不能做啊。。
//646ms 87836kb
#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
//#define gc() getchar()
#define MAXIN 300000
#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
const int N=1e6+3,INF=1e9;//P[7]={2,3,5,7,11,13,17};
int Opt,Ans,A[7],P[7],p[N],cnt[N][20],s[N];//A[N][7],P[N][7] //卡我記憶體還行
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
void Init(const int n)
{
static int P[N>>3];
static bool not_P[N];
for(int cnt=0,i=2; i<=n; ++i)
{
if(!not_P[i]) P[++cnt]=i, p[i]=i;
for(int j=1,v; j<=cnt&&(v=i*P[j])<=n; ++j)
{
not_P[v]=1, p[v]=P[j];
if(!(i%P[j])) break;
}
}
}
int Div(int x)
{
int lim=-1,cnt;
while(x!=1)
{
P[++lim]=p[x], cnt=0;
while(!(x%P[lim])) ++cnt, x/=P[lim];
A[lim]=cnt;
}
return lim;
}
void DFS(int x,int sum,int d)
{
if(x==-1)
{
switch(Opt)
{
case 0: if(++cnt[d][sum]==1) s[d]^=1<<sum; break;
case 1: if(--cnt[d][sum]==0) s[d]^=1<<sum; break;
case 2: if(s[d]) Ans=std::min(Ans,sum+__builtin_ctz(s[d])); break;
}
return;
}
for(int i=0; i<=A[x]; ++i)
DFS(x-1,sum+A[x]-i,d), d*=P[x];
}
int main()
{
Init(1000000);
for(int x,tot=0,Q=read(); Q--; )
{
Opt=read()-1, x=read();
if(Opt==2)
if(tot) Ans=INF;
else {puts("-1"); continue;}
else if(cnt[x][0]^Opt) continue;
DFS(Div(x),0,1);
switch(Opt)
{
case 0: ++tot; break;
case 1: --tot; break;
case 2: printf("%d\n",Ans==INF?-1:Ans); break;
}
}
return 0;
}
考試程式碼
B
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define gc() getchar()
#define eps 1e-10
typedef long long LL;
const int N=64;
int n,Enum,H[N],nxt[N<<1],to[N<<1],dgr[N];
double f[N][N];
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void AE(int u,int v)
{
++dgr[v], to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
++dgr[u], to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
}
int DFS(int x,int fa)
{
if(dgr[x]==1&&x!=fa)
for(int i=0; i<=2*n; ++i) f[x][i]=1;
for(int i=H[x],v; i; i=nxt[i])
if((v=to[i])!=fa)
{
DFS(v,x);
for(int d=1; d<=2*n; ++d)
{
if(f[x][d]<eps) f[x][d]=1;
f[x][d]*=(f[v][d-1]*0.5+(d>1?f[v][d-2]*0.5:0));
}
}
for(int i=0; i<=2*n; ++i) printf("f[%d][%d]=%.5lf\n",x,i,f[x][i]);
}
int main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n=read();
for(int i=1; i<n; ++i) AE(read(),read());
double ans=0; int cnt=0;
for(int x=1; x<=n; ++x)
{
if(dgr[x]>1) continue;
++cnt;
for(int i=1; i<=n; ++i)
{
f[i][0]=0;
for(int j=1; j<=2*n; j+=4) f[i][j]=f[i][j+1]=f[i][j+2]=f[i][j+3]=0;
f[i][2*n-2]=f[i][2*n-1]=f[i][2*n]=0;
}
printf("\nnow:%d\n",x);
DFS(x,x);
for(int i=1; i<=2*n; ++i) ans+=(f[x][i]-f[x][i-1])*i, printf("ans+=%.5lf*%d=%.5lf\n",f[x][i]-f[x][i-1],i,(f[x][i]-f[x][i-1])*i);
}
printf("%.10lf\n",ans);
printf("%.10lf\n",ans/cnt);
return 0;
}/*
5
1 2 2 3 3 4 4 5
4
1 2 1 3 1 4
7
1 2 2 3 3 4 3 5 4 6 4 7
*/
C
#include <set>
#include <queue>
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
#define MAXIN 300000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e6+5,P[7]={2,3,5,7,11,13,17};//7
int A[N][7],L[N],R[N];
bool vis[N],ins[N];
std::multiset<int> st[130];
char IN[MAXIN],*SS=IN,*TT=IN;
inline int read()
{
int now=0;register char c=gc();
for(;!isdigit(c);c=gc());
for(;isdigit(c);now=now*10+c-'0',c=gc());
return now;
}
inline void Div(int x)
{
vis[x]=1;
for(int s=x,i=0; i<7; ++i)
if(!(x%P[i]))
{
int cnt=1; x/=P[i];
while(!(x%P[i])) ++cnt, x/=P[i];
A[s][i]=cnt;
}
}
int main()
{
// freopen("ex_number1.in","r",stdin);
// freopen(".out","w",stdout);
int Q=read(); const int all=1<<7;
// for(int s=0; s<all; ++s) st[s].insert(-1),st[s].insert(100000000);
for(int x,tot=0,ed=0; Q--; )
{
switch(read())
{
case 1:
{
if(ins[x=read()]) break;
ins[x]=1, ++tot;
if(!vis[x]) Div(x);
R[ed]=x, L[x]=ed, ed=x;
break;
}
case 2:
{
if(!ins[x=read()]) break;
ins[x]=0, --tot;
L[R[x]]=L[x], R[L[x]]=R[x];
if(x==ed) ed=L[x];
break;
}
case 3:
{
x=read();
if(!tot) {puts("-1"); break;}
if(!vis[x]) Div(x);
int *a=A[x],ans=1e9;
for(int i=R[0]; ; i=R[i])
{
int sum=0;
for(int j=0; j<7; ++j) sum+=std::abs(a[j]-A[i][j]);
ans=std::min(ans,sum);
if(i==ed) break;
}
printf("%d\n",ans);
break;
}
}
}
// return 0;
for(int x,tot=0,ed=0; Q--; )
{
switch(read())
{
case 1:
{
if(ins[x=read()]) break;
ins[x]=1, ++tot;
if(!vis[x]) Div(x);
int *a=A[x];
printf("A[%d]: ",x); for(int i=0; i<7; ++i) printf("%d ",a[i]); puts("");
for(int s=0; s<all; ++s)
{
int sum=0;
for(int i=0; i<7; ++i)
sum+=(s>>i&1?a[i]:-a[i]);
st[s].insert(sum);
printf("Insert(%d,%d)\n",s,sum);
}
break;
}
case 2:
{
if(!ins[x=read()]) break;
ins[x]=0, --tot;
int *a=A[x];
for(int s=0; s<all; ++s)
{
int sum=0;
for(int i=0; i<7; ++i)
sum+=(s>>i&1?a[i]:-a[i]);
// printf("Delete(%d)\n",sum);
st[s].erase(st[s].find(sum));
}
break;
}
case 3:
{
x=read();
if(!tot) {puts("-1"); break;}
if(!vis[x]) Div(x);
int *a=A[x],ans=0;
printf("A[%d]: ",x); for(int i=0; i<7; ++i) printf("%d ",a[i]); puts("");
for(int s=0; s<all; ++s)
{
int sum=0;
for(int i=0; i<7; ++i)
sum+=(s>>i&1?a[i]:-a[i]);
// std::multiset<int>::iterator it=st[s].upper_bound(sum);
ans=std::max(ans,std::max(*st[s].rbegin()-sum,sum-*st[s].begin()));
printf("s:%d sum:%d big:%d ",s,sum,*st[s].rbegin());
printf("small:%d\n",*st[s].begin());
// ans=std::min(ans,*it-sum);
// printf("s:%d sum:%d big:%d ",s,sum,*it);
// ans=std::min(ans,sum-*(--it));
// printf("small:%d\n",*it);
}
printf("%d\n",ans);
break;
}
}
}
return 0;
}/*
12
3
1 20
1 15
3 30
1 30
3 30
2 10
3 27
1 15
2 15
2 20
2 30
3 5
*/