博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
湖南集训day6
阅读量:5095 次
发布时间:2019-06-13

本文共 5434 字,大约阅读时间需要 18 分钟。

难度:☆☆☆☆☆☆☆☆

 

 

/*对于第一问:f[i][j]表示前i个数,当前黑板上的数为j的概率当前有三种情况1.当前数不是j的倍数—>黑板上的数字改变。2.当前数是j的倍数且当前数在前i个数中(已经选过)3.当前数是j的倍数且没有选过转移:f[i+1][j]=((j的倍数个数-i)*f[i][j]+f[i][gcd(j,k)])  的平均值  j的倍数个数-i是没选过的j的倍数。对于第二问,考虑博弈论中sg函数。可知sg[i][1]二维含义同f数组)必定为0(最后黑板上剩下1必败)  sg[n][i]=0(选完了必败) 同样枚举上述三种情况,取后续状态mex值即可。*/#include 
#include
#include
#include
#define eps 1e-8#define N 1000using namespace std;inline int gcd(int a, int b){ return b == 0 ? a : gcd(b, a % b);}int sg[N + 5][N + 5], g[N + 5][N + 5], f[N + 5], n, a[N + 5];double dp[N + 5][N + 5], ans = 0;bool getsg(int x, int y){ if (x == 1) return 1; if (sg[x][y] != -1) return sg[x][y]; bool flag = 1; if (f[x] > y) flag &= getsg(x, y + 1); for (int i = 1; i <= n; i++) if (g[x][i] != x) flag &= getsg(g[x][i], y + 1); sg[x][y] = !flag; return sg[x][y];}int main(){ freopen("cards.in", "r", stdin); freopen("cards.out", "w", stdout); scanf("%d", &n); int mx = 0; for (int i = 1; i <= n; i++) { scanf("%d", a + i); mx = max(mx, a[i]); g[0][i] = a[i]; } for (int i = 1; i <= mx; i++) for (int j = 1; j <= n; j++) f[i] += (a[j] % i == 0), g[i][j] = gcd(i, a[j]); dp[0][0] = 1; for (int i = 1; i <= n; i++) for (int j = 0; j <= mx; j++) if (dp[i - 1][j] > eps) { dp[i][j] += dp[i - 1][j] * (f[j] - i + 1) / (n - i + 1); for (int k = 1; k <= n; k++) if (g[j][k] != j) { if (g[j][k] != 1) dp[i][g[j][k]] += dp[i - 1][j] / (n - i + 1); else ans += (i + 1 & 1) * dp[i - 1][j] / (n - i + 1); } } if (n & 1) for (int j = 0; j <= mx; j++) ans += dp[n][j]; printf("%.9lf ", ans); memset(sg, -1, sizeof(sg)); if (getsg(0, 0)) puts("1.000000000"); else puts("0.000000000"); return 0;}

 

 

/*对于60~80分,可以n^2暴力,断掉每条边时,O(N)求每个部分的直径,然后相乘。正解:倒序加边,考虑两棵树合并的时候新直径一定是原来两个直径四个断点任意两个的路径。所以可以首先求LCA倍增处理两点间路径,然后求最大。更新答案要用逆元。 */#include
#include
#include
#define N 100007#define mod 1000000007#define ll long longusing namespace std;int a[N],dep[N],sum[N],fa[N][20],head[N],del[N];int D[N][2],ans[N],f[N],len[N],end[2];int n,m,pre,cnt;struct edge{ int u,v,net;}e[N<<1];inline int read(){ int x=0,f=1;char c=getchar(); while(c>'9'||c<'0'){
if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f;}inline void add(int u,int v){ e[++cnt].u=u;e[cnt].v=v;e[cnt].net=head[u];head[u]=cnt;}void dfs(int u,int from){ fa[u][0]=from;dep[u]=dep[from]+1; sum[u]=sum[from]+a[u]; for(int i=1;i<=19;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for(int i=head[u];i;i=e[i].net) { int v=e[i].v; if(v!=from)dfs(v,u); }return;}int find(int x){ return x==f[x]?x:f[x]=find(f[x]);}int ksm(int a,int b){ int res=1; while(b) { if(b&1) res=1ll*res*a%mod; b>>=1;a=1ll*a*a%mod; }return res%mod;}int lca(int u,int v){ if(dep[u]
=0;i--) { if(fa[u][i]!=fa[v][i]) { u=fa[u][i]; v=fa[v][i]; } }return fa[u][0];}int getlen(int u,int v){ int L=lca(u,v); return sum[u]+sum[v]-2*sum[L]+a[L];}int main(){ freopen("forest.in","r",stdin); freopen("forest.out","w",stdout); int x,y; n=read();pre=1; for(int i=1;i<=n;i++) { a[i]=read();f[i]=i; pre=(ll)pre*a[i]%mod; D[i][0]=D[i][1]=i;len[i]=a[i]; } for(int i=1;i
tmax) { tmax=l; end[0]=D[u][j];end[1]=D[v][k]; } } pre=(ll) pre*ksm(len[u],mod-2)%mod; pre=(ll) pre*ksm(len[v],mod-2)%mod; f[v]=u;len[u]=tmax; for(int j=0;j<2;j++) D[u][j]=end[j]; pre=(ll) pre*len[u]%mod; ans[--t]=pre; } for(int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0;}

 

 

/*这题确实是恶心,并且貌似没有部分分......让我们来瞻仰一下std做法考虑两列的情况。若两列颜色分别为A,B,则A独有的颜色就是A—A∩B ,B同理。若是多列那还是设两边两列为A,B,中间多列为C,那根据题目结论可以知道C一定是A∩B的子集。枚举A中独有颜色个数,B中独有颜色个数与A中相同。若有j独有,i共有C(K,i)*C(k-i+1,j)*C(k-i-j,j)因为每次选择都必须是恰好那些颜色,不能少,所以用总方案数减去不是恰好的就可以了。 */ # include
# include
# include
# include
using namespace std;const int pp=1000000007;int c[2008][2008],f[2008],p[2008],ni[2008];int n,m,k,nn;inline int power(int x,int n){ int ans=1,tmp=x; while (n) { if (n&1) ans=(long long)ans*tmp%pp; tmp=(long long)tmp*tmp%pp;n>>=1; } return ans;}void Count_c(){ for (int i=0;i<=nn;i++) c[i][0]=1; for (int i=1;i<=nn;i++) for (int j=1;j<=i;j++) { c[i][j]=c[i-1][j-1]+c[i-1][j]; if (c[i][j]>=pp) c[i][j]-=pp; }}void Count_p(){ int mm=(m-2)*n; for (int i=0;i<=nn;i++) p[i]=power(i,mm);}void Count_f(){ f[0]=0;f[1]=1; for (int i=2;i<=nn;i++) { f[i]=power(i,n); for (int j=1;j
=pp) sum1-=pp; tmp1=tmp1*ni[j+1]%pp; if (k-s
=pp) sum-=pp; } printf("%d\n",sum); } fclose(stdin); fclose(stdout); return 0;}

 

转载于:https://www.cnblogs.com/L-Memory/p/7650254.html

你可能感兴趣的文章
《梦断代码》读后感3
查看>>
Java探究心得之三元运算符
查看>>
跳跃的舞者,舞蹈链(Dancing Links)算法——求解精确覆盖问题(转)
查看>>
仿新浪手机浏览器www与wap跳转提示
查看>>
P3932 浮游大陆的68号岛
查看>>
Ubuntu 10.10+安装Firefox 4.0正式版
查看>>
Using {{each}} in a template with an array of arrays
查看>>
第五百天 how can I 坚持
查看>>
集合-列表
查看>>
Adobe AIR对本地文件(XML文件)的操作
查看>>
adb 模拟器安装apk
查看>>
html5 图表相关
查看>>
咏南开发框架之自动升级
查看>>
简单MIS的构想
查看>>
简洁的ios小界面
查看>>
linux下mysql远程链接
查看>>
提取汉字拼音的首字母
查看>>
mysql快速入门
查看>>
JavaScript(五)语句
查看>>
jsvascript === 和==的区别
查看>>