2017/11/5模拟赛总结
来源:互联网 发布:马里亚纳网络为何恐怖 编辑:程序博客网 时间:2024/06/17 15:24
T1 放数字游戏
可以通过考虑一个点和前面某个点的贡献入手
假设当前前面的点为
那么
而
所以可以枚举
显然
那么扫一遍就可以了
#include<bits/stdc++.h>using namespace std;#define N 200010#define mo 1000000007int n,a[N];int Pow[N];void init(){ int i; Pow[0]=1; for (i=1;i<=n;i++) Pow[i]=Pow[i-1]*2%mo;} int main(){ int i; scanf("%d",&n); for (i=0;i<=n;i++) scanf("%d",&a[i]); init(); int sum=a[0],ans=0; for (i=1;i<=n;i++){ ans=(ans+2LL*sum*a[i]%mo*Pow[n-i])%mo; sum=(sum+1LL*a[i]*Pow[i-1])%mo; } printf("%d\n",ans); return 0;}
T2 电缆建设
这是一个平面上的最小生成树问题
特殊之处在于所有点都排成两列
解法1
直接建边是
一个点如果要和对面的点相连 一定和纵坐标相邻的点连边更优
那么可以建一颗有
但是由于排序需要较多时间 会被卡常
解法2
考虑dp
由于只有相邻的边连边可能作为答案 所以可以时刻让
然后可以同时滚动
这样dp数组只需要
第一次写同时滚动两维的dp 比较麻烦
要注意数组的清空问题
#include<bits/stdc++.h>using namespace std;#define N 1000010#define EPS 1e-6inline void rd(int &x){ char c;x=0; while (c=getchar(),c<48); do x=(x<<1)+(x<<3)+(c^48); while (c=getchar(),c>=48);}int n,m,a[N],b[N];double dp[2][2][2];long long X;#define dis(x,y) sqrt(X+1LL*(a[x]-b[y])*(a[x]-b[y]))inline void Dp(int f1,int f2,int i,int j){ dp[f1][f2][0]=dp[f1][f2][1]=1e9; dp[!f1][!f2][0]=dp[!f1][!f2][1]=1e9; dp[f1][f2][0]=min(dp[f1][f2][0],min(dp[!f1][f2][0]+(a[i]-a[i-1]),dp[!f1][f2][1])); dp[f1][f2][0]=min(dp[f1][f2][0],min(dp[f1][!f2][0]+(b[j]-b[j-1]),dp[f1][!f2][1])); dp[f1][f2][1]=min(dp[f1][f2][1],min(min(dp[!f1][f2][1]+(a[i]-a[i-1]),dp[!f1][f2][1]+dis(i,j)),dp[!f1][f2][0]+(a[i]-a[i-1])+dis(i,j))); dp[f1][f2][1]=min(dp[f1][f2][1],min(min(dp[f1][!f2][1]+(b[j]-b[j-1]),dp[f1][!f2][1]+dis(i,j)),dp[f1][!f2][0]+(b[j]-b[j-1])+dis(i,j)));} int main(){ int i,j,X1,X2; rd(n),rd(m),rd(X1),rd(X2); X=1LL*(X1-X2)*(X1-X2); for (i=1;i<=n;i++) rd(a[i]),a[i]+=a[i-1]; for (i=1;i<=m;i++) rd(b[i]),b[i]+=b[i-1]; dp[0][0][0]=dp[0][0][1]=dp[0][1][0]=dp[0][1][1]=dp[1][0][0]=dp[1][0][1]=1e9; dp[1][1][0]=0; dp[1][1][1]=dis(1,1); int f1=1,f2=1; for (i=1,j=1;i<=n;i++,f1^=1){ while (j<=m && b[j-1]<=a[i]){ if (i==1 && j==1){ j++; f2^=1; continue; } Dp(f1,f2,i,j); j++; f2^=1; } j--; f2^=1; } f1^=1; for (j=j+1,f2^=1;j<=m;j++,f2^=1) Dp(f1,f2,n,j); f2^=1; printf("%.2f\n",dp[f1][f2][1]); return 0;}
T3 抢座位
首先有一个比较显然的性质:若第
可以dfs每个固定位置的人最后在什么位置
那么每次需要知道当前已经有人的位置 和已经选好位置的人数
在比当前人编号小的人里面 可以选出一些在当前人的前面
这些人的位置又不固定
所以要用排列组合算出方案数
全部确定完之后可能还有人没有固定 要再排列一下
而由于可以通过可行性剪枝剪掉很多不合法的情况 dfs还是很快的
位置的状态可以用二进制压位表示
极限为
#include<bits/stdc++.h>using namespace std;#define N 35int n,m,mo,C[N][N],fac[N];struct node{ int x,y; bool operator <(const node &_)const{ return x<_.x; }}a[N];bool mark[N];int ans;void init(){ int i,j; for (i=0;i<=n;i++){ C[i][0]=1; for (j=1;j<=i;j++) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mo; } fac[0]=1; for (i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%mo;}void dfs(int l,int sum,int Mk){ if (l>m){ ans=(ans+1LL*sum*fac[n-Mk])%mo; return; } int i,cnt=0,tmp=0; bool cop[N]; for (i=a[l].y;i<=a[l].x+a[l].y-1 && i<=n;i++){ if (mark[i]){ cnt++; continue; } mark[i]=1; tmp++; memcpy(cop,mark,sizeof(cop)); if (a[l].x-1-Mk<0 || i-a[l].y-cnt<0) return; dfs(l+1,1LL*sum*C[a[l].x-1-Mk][i-a[l].y-cnt]%mo*fac[i-a[l].y-cnt]%mo,Mk+tmp); memcpy(mark,cop,sizeof(cop)); }}int main(){ int i; scanf("%d%d%d",&n,&m,&mo); for (i=1;i<=m;i++) scanf("%d%d",&a[i].x,&a[i].y); init(); sort(a+1,a+1+m); dfs(1,1,0); printf("%d\n",ans); return 0;}
NOIP2017 倒计时6天
今天没有犯低级错误 只是第二题常数太大
排序时尽量不要用double 比如根号可以先存longlong下的没开根的数
因为不判EPS可能会出现精度问题
判了又会使排序常数大大增加
Date:2017/11/5
By CalvinJin
- 2017/11/5模拟赛总结
- 2017/11/3模拟赛总结
- 2017/11/4模拟赛总结
- 2017/11/6模拟赛总结
- 2017/11/7模拟赛总结
- 2017/11/8模拟赛总结
- 2017/11/9模拟赛总结
- NOIP2017模拟赛(11) 总结
- NOIP2017模拟赛(5) 总结
- 2017/10/7模拟赛总结
- 2017/10/9模拟赛总结
- 2017/10/10模拟赛总结
- 2017/10/6模拟赛总结
- 2017/10/12模拟赛总结
- 2017/10/15模拟赛总结
- 2017/10/16模拟赛总结
- 2017/10/21模拟赛总结
- 2017/10/23模拟赛总结
- 顺序表的实现
- ubuntu16.04下安装NVIDIA(cuda)-gtx965m相关步骤以及问题
- Lua语法分析(2)- 控制语句
- 你经历过绝望吗?两次! CSU
- Ionic3 Tips
- 2017/11/5模拟赛总结
- 十进制转二进制、二进制转十进制
- 机房收费系统之完结篇
- zcmu-1984
- 【正明吉利】烟雾阴霾一扫而光 -吉利生态净化舱
- python初试——模拟登陆
- hiho1619“共同富裕”
- 数据库优化
- 快速幂 & 素数筛法