2017-10-18 NOIP模拟赛
纸牌游戏
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cstdlib>
#define maxn 301
using namespace std;
int n,a[maxn],q[maxn],cnt[maxn];
long long sz[maxn];
bool vis[maxn];
int gcd(int x,int y){
if(y==)return x;
else return gcd(y,x%y);
}
void dfs(int pos,int now){
if(clock()>=){
puts("0.000000000 1.000000000");
exit();
}
if(now==){
if((pos&)==)cnt[pos]++;
return;
}
for(int i=;i<=n;i++){
if(!vis[i]){
vis[i]=;
dfs(pos+,gcd(now,a[i]));
vis[i]=;
}
}
}
int main(){
//freopen("Cola.txt","r",stdin);
freopen("cards.in","r",stdin);freopen("cards.out","w",stdout);
scanf("%d",&n);
sz[]=n;
for(int i=;i<=n;i++)sz[i]=sz[i-]*(n-i+);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
dfs(,);
double ans=;
for(int i=;i<=n;i+=)
ans+=(double)cnt[i]/(double)sz[i];
printf("%.9lf ",ans);
puts("1.000000000");
}
64分 dfs+输出1
/*
对于第一问: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 ;
}
100分 概率DP+博弈论
秀秀的森林
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100010
#define mod 1000000007
using namespace std;
int n,q[maxn],fa[maxn],sz[maxn],w[maxn],cut[maxn],ans,map[maxn];
int num,head[maxn],mx[maxn],vis[maxn];
struct node{
int from,to;
}E[maxn];
struct Node{
int to,pre;
}e[maxn];
int find(int x){
if(x==fa[x])return x;
else return fa[x]=find(fa[x]);
}
void dfs(int x,int father,int stx,int sty,int wnow){
for(int i=head[x];i;i=e[i].pre){
int to=e[i].to;
if(to==father)continue;
if(mx[to]<mx[sty]+wnow+w[to]){
mx[to]=mx[sty]+wnow+w[to];
map[to]=map[sty];
dfs(to,x,stx,sty,wnow+w[to]);
}
}
}
void connect(int x,int y){
int f1=find(x),f2=find(y);
int now=mx[x]+mx[y];
fa[f2]=f1;
if(now>sz[f1]&&now>sz[f2]){
sz[f1]=now;
sz[f2]=;
}
else{
sz[f1]=max(sz[f1],sz[f2]);
sz[f2]=;
}
dfs(x,x,x,y,w[x]);
dfs(y,y,y,x,w[y]);
int xx=map[x],yy=map[y];
int maxx=mx[x],maxy=mx[y];
map[map[x]]=yy;map[map[y]]=xx;
if(mx[x]<maxy+w[x]){mx[x]=maxy+w[x];map[x]=yy;}
if(mx[y]<maxx+w[y]){mx[y]=maxx+w[y];map[y]=xx;}
}
void Insert(int from,int to){
e[++num].to=to;
e[num].pre=head[from];
head[from]=num;
e[++num].to=from;
e[num].pre=head[to];
head[to]=num;
}
int qread(){
int i=;
char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch<=''&&ch>=''){i=i*+ch-'';ch=getchar();}
return i;
}
int main(){
freopen("forest.in","r",stdin);freopen("forest.out","w",stdout);
//freopen("Cola.txt","r",stdin);
n=qread();
q[n]=;
for(int i=;i<=n;i++){
w[i]=qread();
fa[i]=i,sz[i]=w[i];
mx[i]=w[i];
map[i]=i;
q[n]=(1LL*w[i]*q[n])%mod;
}
for(int i=;i<n;i++)scanf("%d%d",&E[i].from,&E[i].to);
for(int i=;i<n;i++)scanf("%d",&cut[i]);
for(int i=n-;i>=;i--){
connect(E[cut[i]].from,E[cut[i]].to);
Insert(E[cut[i]].from,E[cut[i]].to);
long long ans=;
memset(vis,,sizeof(vis));
for(int j=;j<=n;j++){
int now=find(j);
if(!vis[now]){
vis[now]=;
ans=ans*sz[now];
if(ans>=mod)ans%=mod;
}
}
q[i]=(int)ans;
//for(int j=1;j<=n;j++)printf("%d %d %d\n",j,map[j],mx[j]);puts("");
}
for(int i=;i<=n;i++){
printf("%d\n",q[i]);
}
return ;
}
/*
8
2 3 6 3 9 4 5 6
4 8
3 5
4 1
1 3
1 2
6 5
7 5
2
6
3
1
7
4
5
*/
10分 并查集
/*
对于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 ;
}
100分
#include<iostream>
#include<cstdio>
#include<cstring>
#ifdef WIN32
#define mod 1000000007
#define PLL "%I64d"
#else
#define PLL "%lld"
#endif
#define maxn 100010
using namespace std;
int w[maxn],head[maxn],n,dis[maxn];
bool vis[maxn];
struct node{
int to,pre,v;
}e[maxn*];
void Insert(int from,int to,int v,int id){
e[id].to=to;
e[id].v=v;
e[id].pre=head[from];
head[from]=id;
}
void dfs(int now,int father){
for(int i=head[now];i;i=e[i].pre){
int to=e[i].to;
if(to==father)continue;
if(e[i].v==)continue;
vis[to]=;
dis[to]=dis[now]+w[to];
dfs(to,now);
}
}
int zhijing(int x){
memset(dis,,sizeof(dis));
dis[x]=w[x];
dfs(x,x);
int mx=,now=;
for(int i=;i<=n;i++)
if(dis[i]>mx){
mx=dis[i];
now=i;
}
if(now==x)return mx;
memset(dis,,sizeof(dis));
dis[now]=w[now];
dfs(now,now);
for(int i=;i<=n;i++)
if(dis[i]>mx)mx=dis[i];
return mx;
}
int main(){
freopen("forest.in","r",stdin);freopen("forest.out","w",stdout);
//freopen("Cola.txt","r",stdin);
scanf("%d",&n);
int x,y;
for(int i=;i<=n;i++)scanf("%d",&w[i]);
for(int i=;i<n;i++){
scanf("%d%d",&x,&y);
Insert(x,y,,i);Insert(y,x,,i+n);
}
printf("%d\n",zhijing());
for(int i=;i<n;i++){
scanf("%d",&x);
e[x].v=;e[x+n].v=;
memset(vis,,sizeof(vis));
long long ans=;
for(int j=;j<=n;j++){
if(!vis[j]){
vis[j]=;
ans=ans*zhijing(j);
if(ans>=mod)ans%=mod;
}
}
printf(PLL"\n",ans);
}
}
40分 最裸的暴力
秀秀的照片
/*
这题确实是恶心,并且貌似没有部分分......
让我们来瞻仰一下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 ;
}
100分 组合数学
2017-10-18 NOIP模拟赛的更多相关文章
- 2017 10.25 NOIP模拟赛
期望得分:100+40+100=240 实际得分:50+40+20=110 T1 start取了min没有用,w(゚Д゚)w O(≧口≦)O T3 代码3个bug :数组开小了,一个细节没注意, ...
- 10.17 NOIP模拟赛
目录 2018.10.17 NOIP模拟赛 A 咒语curse B 神光light(二分 DP) C 迷宫maze(次短路) 考试代码 B 2018.10.17 NOIP模拟赛 时间:1h15min( ...
- 10.16 NOIP模拟赛
目录 2018.10.16 NOIP模拟赛 A 购物shop B 期望exp(DP 期望 按位计算) C 魔法迷宫maze(状压 暴力) 考试代码 C 2018.10.16 NOIP模拟赛 时间:2h ...
- 2016.10.30 NOIP模拟赛 day2 PM 整理
满分:300分 直接全部爆零,真的是很坑啊! 10.30的题目+数据:链接:http://pan.baidu.com/s/1jHXLace 密码:i784 T1: 题目中的难点就是每次折叠的点可能应经 ...
- 2018.10.16 NOIP模拟赛解题报告
心路历程 预计得分:\(100 + 100 + 20 = 220\) 实际得分:\(100 + 100 + 30 = 230\) 辣鸡模拟赛.. T1T2都是一眼题,T3考验卡常数还只有一档暴力分. ...
- 2016.10.30 NOIP模拟赛 day2 AM 整理
题目+数据:链接:http://pan.baidu.com/s/1gfBg4h1 密码:ho7o 总共得了:130分, 1:100分 2:30分(只会这30分的暴力) 3:0(毫无思路) 虽然不高, ...
- 10.18 noip模拟试题
分火腿 (hdogs.pas/.c/.cpp) 时间限制:1s:内存限制 64MB 题目描述: 小月言要过四岁生日了,她的妈妈为她准备了n根火腿,她想将这些火腿均分给m位小朋友,所以她可能需要切火腿. ...
- 2017.5.27 NOIP模拟赛(hzwer2014-5-16 NOIP模拟赛)
期望得分:100+100+60+30=290 实际得分:100+20+60+0=180 当务之急:提高一次正确率 Problem 1 双色球(ball.cpp/c/pas) [题目描述] 机房来了新一 ...
- 2017.6.11 NOIP模拟赛
题目链接: http://files.cnblogs.com/files/TheRoadToTheGold/2017-6.11NOIP%E6%A8%A1%E6%8B%9F%E8%B5%9B.zip 期 ...
- 2018.10.03 NOIP+ 模拟赛 解题报告
得分: \(30+5+0=35\)(考得真不咋滴) \(T1\):奥义商店(点此看题面) 以为很简单,对着这题想了一个多小时,最后果断打了个暴力交了... ... 看完题解发现其实也不是很难. 对于\ ...
随机推荐
- node.js+express+jade系列四:jade嵌套的使用
jade是express自带的模板引擎 jade文件可以嵌套使用,include引用外部jade文件,extends引用jade模板 例如 有一个主jade文件layout.jade,引用top.ja ...
- Quality
- adb命令(一)
针对移动端 Android 的测试, adb 命令是很重要的一个点,必须将常用的 adb 命令熟记于心, 将会为 Android 测试带来很大的方便,其中很多命令将会用于自动化测试的脚本当中. And ...
- 如何使 vlc 支持 fdk-aac 编码(windows平台
可能是由于fdk-aac开源协议的原因,VLC默认是不支持fdk-aac编码的,fdk-aac 是非常优秀的AAC编码库,并且支持AAC-LD AAC-ELD, 对于要求低延迟的场景下很有用. 可以通 ...
- Agc010_D Decrementing
今天本人因调了上篇博客的题而脑壳不适,不想颓题,因此有了这篇博客. 但是博客毕竟得讲点什么,想想有没有什么代码短的. 哦,好像有,就Agc010_D Decrementing好了. Alice和Bob ...
- CH#56C 异象石 和 BZOJ3991 [SDOI2015]寻宝游戏
异象石 CH Round #56 - 国庆节欢乐赛 描述 Adera是Microsoft应用商店中的一款解谜游戏. 异象石是进入Adera中异时空的引导物,在Adera的异时空中有一张地图.这张地图上 ...
- 1. Two Sum[LeetCode 简单 by 大志]
1. 二数之和 题目 English Given an array of integers, return indices of the two numbers such that they add ...
- Python:代码单元、代码点介绍
转于:https://www.cnblogs.com/runwulingsheng/p/5106078.html 博主:你是那天边突然划过的一道闪电 代码点:指编码表(比如Unicode)中某个字符的 ...
- 0008_Python变量
1.变量名:数字,字母,下划线组成,不能以数字开头,不能是Python内部关键字. 2.变量类型:数字,字符串,布尔值(首字母大写) 3.内存与变量: 4. = 赋值 == 比较 is == ...
- Python数据结构与算法设计(总结篇)
的确,正如偶像Bruce Eckel所说,"Life is short, you need Python"! 如果你正在考虑学Java还是Python的话,那就别想了,选Pytho ...