难度:☆☆☆☆☆☆☆☆

/*
对于第一问: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 <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define N 1000
using namespace std;
inline int gcd(int a, int b)
{
return b == ? a : gcd(b, a % b);
}
int sg[N + ][N + ], g[N + ][N + ], f[N + ], n, a[N + ];
double dp[N + ][N + ], ans = ;
bool getsg(int x, int y)
{
if (x == ) return ;
if (sg[x][y] != -) return sg[x][y];
bool flag = ;
if (f[x] > y) flag &= getsg(x, y + );
for (int i = ; i <= n; i++)
if (g[x][i] != x)
flag &= getsg(g[x][i], y + );
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 = ;
for (int i = ; i <= n; i++)
{
scanf("%d", a + i);
mx = max(mx, a[i]);
g[][i] = a[i];
}
for (int i = ; i <= mx; i++)
for (int j = ; j <= n; j++)
f[i] += (a[j] % i == ), g[i][j] = gcd(i, a[j]);
dp[][] = ;
for (int i = ; i <= n; i++)
for (int j = ; j <= mx; j++)
if (dp[i - ][j] > eps)
{
dp[i][j] += dp[i - ][j] * (f[j] - i + ) / (n - i + );
for (int k = ; k <= n; k++)
if (g[j][k] != j)
{
if (g[j][k] != )
dp[i][g[j][k]] += dp[i - ][j] / (n - i + );
else
ans += (i + & ) * dp[i - ][j] / (n - i + );
}
}
if (n & )
for (int j = ; j <= mx; j++) ans += dp[n][j];
printf("%.9lf ", ans);
memset(sg, -, sizeof(sg));
if (getsg(, )) puts("1.000000000");
else puts("0.000000000");
return ;
}

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

/*
这题确实是恶心,并且貌似没有部分分......
让我们来瞻仰一下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<iostream>
# include<cstdio>
# include<cstring>
# include<cstdlib> using namespace std;
const int pp=;
int c[][],f[],p[],ni[];
int n,m,k,nn; inline int power(int x,int n)
{
int ans=,tmp=x;
while (n)
{
if (n&) ans=(long long)ans*tmp%pp;
tmp=(long long)tmp*tmp%pp;n>>=;
}
return ans;
} void Count_c()
{
for (int i=;i<=nn;i++) c[i][]=;
for (int i=;i<=nn;i++)
for (int j=;j<=i;j++)
{
c[i][j]=c[i-][j-]+c[i-][j];
if (c[i][j]>=pp) c[i][j]-=pp;
}
} void Count_p()
{
int mm=(m-)*n;
for (int i=;i<=nn;i++)
p[i]=power(i,mm);
} void Count_f()
{
f[]=;f[]=;
for (int i=;i<=nn;i++)
{
f[i]=power(i,n);
for (int j=;j<i;j++)
{
f[i]-=(long long)f[j]*c[i][j]%pp;
if (f[i]<=-pp) f[i]+=pp;
}
if (f[i]<) f[i]+=pp;
}
} void Count_ni()
{
ni[]=;
for (int i=;i<=nn;i++)
ni[i]=power(i,pp-);
} int main()
{
freopen("photo.in","r",stdin);
freopen("photo.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
nn=min(n,k);
if (m==)
printf("%d\n",power(k,n));
else
{
Count_c();Count_p();
Count_f();Count_ni();
long long tmp=,tmp1=,sum=,sum1;
for (int s=;s<=nn;s++)
{
tmp=tmp*ni[s]%pp;
tmp=tmp*(k-s+)%pp;
tmp1=;sum1=;
for (int j=;j<=s;j++)
{
sum1+=tmp1*c[s][s-j]%pp*p[s-j]%pp;
if (sum1>=pp) sum1-=pp;
tmp1=tmp1*ni[j+]%pp;
if (k-s<j+) break;
tmp1=tmp1*(k-s-j)%pp;
}
sum+=tmp*f[s]%pp*f[s]%pp*sum1%pp;
if (sum>=pp) sum-=pp;
}
printf("%d\n",sum);
}
fclose(stdin);
fclose(stdout);
return ;
}

湖南集训day6的更多相关文章

  1. 主席树 || 可持久化线段树 || BZOJ 3653: 谈笑风生 || Luogu P3899 [湖南集训]谈笑风生

    题面:P3899 [湖南集训]谈笑风生 题解: 我很喜欢这道题. 因为A是给定的,所以实质是求二元组的个数.我们以A(即给定的P)作为基点寻找答案,那么情况分两类.一种是B为A的父亲,另一种是A为B的 ...

  2. LOJ #6074. 「2017 山东一轮集训 Day6」子序列

    #6074. 「2017 山东一轮集训 Day6」子序列 链接 分析: 首先设f[i][j]为到第i个点,结尾字符是j的方案数,这个j一定是从i往前走,第一个出现的j,因为这个j可以代替掉前面所有j. ...

  3. P3900 [湖南集训]图样图森破

    P3900 [湖南集训]图样图森破 链接 分析: 感觉像个暴力. 可以枚举回文串的回文中心,即枚举一个串,枚举一个串的位置作为回文中心,然后求出这个串内的回文串的长度. 此时如果回文串两端都没有到这个 ...

  4. 2019暑期金华集训 Day6 杂题选讲

    自闭集训 Day6 杂题选讲 CF round 469 E 发现一个数不可能取两次,因为1,1不如1,2. 发现不可能选一个数的正负,因为1,-1不如1,-2. hihoCoder挑战赛29 D 设\ ...

  5. 2019暑期金华集训 Day6 计算几何

    自闭集训 Day6 计算几何 内积 内积不等式: \[ (A,B)^2\le (A,A)(B,B) \] 其中\((A,B)\)表示\(A\cdot B\). (好像是废话?) 叉积 \[ A\tim ...

  6. 考前停课集训 Day6 垒

    Day 6 今天在家里的 家里蹲 其实是day7的时候想到要写day6了 草率补充一下 NOIP考前棕名退不掉咯 你觉得我还会打洛谷的题目吗? 依然退步 没用心 T1 分火腿 数论题 我感觉挺难的 T ...

  7. 2022寒假集训day6

    day6上午还是做四道题T1区域[上机练习]1.编程计算由"*"号围成的下列图形的面积.面积计算方法是统计*号所围成的闭合曲线中水平线和垂直线交点的数目.如下图所示,在 10*10 ...

  8. 省队集训day6 C

    Description 给定平面上的 N 个点, 其中有一些是红的, 其他是蓝的.现在让你找两条平行的直线, 使得在保证    不存在一个蓝色的点 被夹在两条平行线之间,不经过任何一个点, 不管是蓝色 ...

  9. 省队集训day6 B

    一道AC自动机题···· 一定要把一个节点没有的儿子接到它fai的儿子,否则会卡到n^2的······· #include<cstdio> #include<iostream> ...

随机推荐

  1. 深入理解DOM事件类型系列——剪贴板事件

    定义 剪贴板操作包括剪切(cut).复制(copy)和粘贴(paste)这三个操作,快捷键分别是ctrl+x.ctrl+c.ctrl+v.当然也可以使用鼠标右键菜单进行操作 对象事件 关于这3个操作共 ...

  2. 洛谷——P3946 ことりのおやつ(小鸟的点心)

    P3946 ことりのおやつ(小鸟的点心) 题目太长,请去链接里看吧 注意细节:特判终点(即使困住又能怎样,到达就好了),特判高度 #include<bits/stdc++.h> #defi ...

  3. 透彻分析C/C++中memset函数

    在C语言中,经常需要对内存进行操作,里面涉及很多函数,但是memset函数的使用有一点需要大家格外注意,这也是我在做项目时遇到过的一个问题,调试了很久才找出来错误. 函数原型是:void *memse ...

  4. Fleecing the Raffle(NCPC 2016 暴力求解)

    题目: A tremendously exciting raffle is being held, with some tremendously exciting prizes being given ...

  5. HDU_5783_DivideTheSequence

    HDU_5783_DivideTheSequence  点击打开链接 题意: 生成尽量多的连续的子串,且子串的前缀和大于等于0,输出符合题意的子串的数量. 这题目是参加四月份的个人训练赛遇到的,挺水的 ...

  6. linux常用操作记录

    vim:多行注释 vim中多行注释和多行删除命令,这些命令也是经常用到的一些小技巧,可以大大提高工作效率.   多行注释:   1. 首先按esc进入命令行模式下,按下Ctrl + v,进入列(也叫区 ...

  7. RANS VS LES

    Turbulence models

  8. vue-router2.0二级路由的简单使用

    1.app.vue中 <template> <div id="app"> <router-view></router-view> & ...

  9. DemoKit编译过程

    E:\Project_code\EAE\src_rev_24139_A95LYD\Project\DemoKit>make release Checking uITRON - DemoKit r ...

  10. c# 缓存!

    做项目的时候获取所有城市的时候,发现每次去获取都花费了很多时间,所以用缓存方法让效率更高! 这是我做的例子,如下: public class CacheGetCity { /// <summar ...