2017.7 13 NOIP模拟赛
来源:互联网 发布:内存卡数据恢复软件 编辑:程序博客网 时间:2024/06/06 17:21
2017.7 13 模拟
全国信息学分区联赛模拟试题(五)
本人分数:190 (其实120 小小改动了一下才190)
【试题概览】
1.序列
【题目描述】
有一个整数序列,它的每个数各不相同,我们不知道它的长度是多少(即整数个数),但我但我
们知道在某些区间中至少有多少个整数,用区间(Li,Ri,Ci)来描述,表示这个整数序列中至
少有 Ci 个数来自区间[Li,Ri],给出若干个这样的区间,问这个整数序列的长度最少能为多
少?
【输入文件】
第一行一个整数 N,表示区间个数;
接下来 N 行,每行三个整数(Li,Ri,Ci),描述一个区间。
【输出文件】
仅一个数,表示该整数序列的最小长度。
【样例输入】
4
4 5 1
6 10 3
7 10 3
5 6 1
【样例输出】
4
【数据规模】
N<=1000,0<=Li<=1000,1<=Ci<=Ri-Li+1
题解
差分约束 同洛谷的某题 种树
差分约束维护的是一个前缀和
满足下面的式子
所以可以差分约束连边
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#define inf 0x7ffffff#define N 10005using namespace std;struct edge{int to,next,w;}e[1000001];int head[N],d[N],cnt,start,flag[N];queue<int>q;int end=1;void insert(int x,int y,int z){e[++cnt].to=y;e[cnt].w=z;e[cnt].next=head[x];head[x]=cnt;}void spfa(){ memset(d,-1,sizeof(d)); q.push(start); d[start]=0; while(!q.empty()) { int k=q.front();q.pop();flag[k]=0; for(int i=head[k];i;i=e[i].next){ int kk=e[i].to; if(d[kk]<d[k]+e[i].w){ d[kk]=d[k]+e[i].w; if(!flag[kk]){ flag[kk]=1; q.push(kk); } } } }}int main(){ freopen("sequence.in","r",stdin); freopen("sequence.out","w",stdout); int n;int x,y,c; scanf("%d",&n); start=0; for(int i=1;i<=n;i++){ scanf("%d%d%d",&x,&y,&c); if(c==0) continue; insert(x-1,y,c); end=max(end,y); } for(int i=1;i<=end;i++){ insert(i-1,i,0);insert(i,i-1,-1); } for(int i=1;i<=end;i++) insert(start,i,0); spfa(); //printf("%d",end); printf("%d",d[end]); return 0;}
2. 矩形
【题目描述】
给你个 01 矩阵,问共有多少个不同的全 0 矩阵?
【输入文件】
第一行两个整数 N,M;
接下来 N 行,每行 M 个字符,如果字符为‘.’,表示这格可行(即表示数字 0);
如果为’×’,表示不可行(即表示数字 1)。
【输出文件】
一个数表示答案。
【样例输入】
6 4
. . . .
.× × ×
.× . .
.× × ×
. . .×
.× × ×
【样例输出】
38
【数据规模】
30%的数据,N,M<=50;
100%的数据,N,M<=200.
题解
枚举矩形的上界和下界
当上界 下界所夹的区间
有x就把这一个区间打上标记
设两个有x的矩形所夹的矩形长度为d
那么 这中间就会有(d*(d+1))/2个矩形
枚举上下界的时间复杂度为n^2 扫描的复杂度为m
所以是O(n^2m)的复杂度
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>using namespace std;int mp[250][250];int cnt[250];int ans;int main(){ freopen("rectangle.in","r",stdin); freopen("rectangle.out","w",stdout); int n,m; char tmp[250]; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",tmp+1); for(int j=1;j<=m;j++) { if(tmp[j]=='*') mp[i][j]=1; } } for(int i=1;i<=n;i++){//i上界j下界 memset(cnt,0,sizeof(cnt)); for(int j=1;j<=m;j++){ if(mp[i][j]) cnt[j]++; } for(int j=i+1;j<=n+1;j++){//更新第j行 实际上是在更新第j-1行 所以到n+1 int pre=0; for(int k=1;k<=m;k++){ if(!cnt[k]) continue; int len=k-pre-1; ans+=len*(len+1)/2; pre=k; } if(pre!=m){ int len=m-pre; ans+=len*(len+1)/2; } for(int k=1;k<=m;k++){ if(mp[j][k]) cnt[k]++;//当前行更新cnt值 } } } printf("%d",ans); return 0;}
3 . 锁
【题目描述】
给出 N 和 K,要求生成从 0 到 2^N-1 的一个序列,序列的第一项为 0,并且该序
列满足以下三个条件:
(1)序列长度为 2^N,保证 0 到 2^N-1 每个数都用了且只用了一次。
(2)序列中任意两相邻的数都是由前一个数在其二进制下,改变了具有相同值
的若干位而形成的,即把其中若干个 0 变为 1,或把其中若干个 1 变成 0,并且
只能 2 选 1.
(3)当存在多个序列满足前两个条件的时候,要保证字典序最小,即由前一个
数生成后一个数的时候,要挑值最小的数(当然是满足前两个条件的情况下)。
现在问你这个序列前 K 项中的最大值是多少,输出其二进制形式,注意一定要
输出 N 位,包括前导零。
【输入文件】
仅一行,两个整数 N,K。
【输出文件】
一个二进制的数,为所求的答案。
【样例输入】
3 8
【样例输出】
111
【样例解释】
整个序列为“000”,“001”,“011”,“010”,“110”,“100”,“101”,“111”。
【数据规模】
1<=N<=50,1<=K<=2^N,注意 K 可能超过 longint。
题解
手写n=1,2,3,4的情况
会找到规律(看题解)
每次可以把2^n个数劈成两半
那么 第2^(n-1)+1 个数是第2^(n-1)+ 2^(n-1)得来的
就是二进制的第i位加了1
然后会发现 前面的2^i-1个数的第i位为1
就可以得到第2^(i-1)+1 后面的数
eg:
n=3 有
000 001 011 010 ==|== 110 100 101 111
中间分一半的话 后面的都是前面的第n位为1得来的
graph LR010-->110000-->100001-->101011-->111
那么根据这个规律就可以找到n为定值时的第k个
比较是 因为前2^n 个最大的是2^n-1 所以进行比较
都是一个递归过程
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#define ll long long using namespace std;ll a;ll b;ll getnum(ll n,ll k){ if(n==0) return 0; ll half=(1ll<<(n-1)); if(k<=half) return getnum(n-1,k); else if(k==half+1) return getnum(n-1,half)+half; else return getnum(n-1,k-half-1)+half;}ll getmax(ll n,ll k){ if(n==0) return 0; ll half=(1ll<<(n-1)); if(k<=half) return getmax(n-1,k); else { ll tmp=getnum(n,half+1); if(k==half+1) return tmp; else return max(tmp,getmax(n-1,k-half-1)+half); }}int out[15000];int main(){ freopen("lock.in","r",stdin); freopen("lock.out","w",stdout); scanf("%lld%lld",&a,&b); ll ans=getmax(a,b); //printf("%lld\n",ans); // printf("%lld\n",ans); for(int i=a-1;i>=0;i--){ cout<<(((1ll<<i)&ans)?"1":"0"); } return 0;}
4 、 看守
【题目描述】
给出 D 维空间的 N 个点,求曼哈顿距离最大的两个点的曼哈顿距离。两个 D 维
的点(x1,x2,…xD),(y1,y2,…yD)的曼哈顿距离定义为
\sum_i |xi-yi|
【输入文件】
第一行两个整数 N,D;
接下来 N 行,每行 D 个整数描述一个点的坐标。
【输出文件】
输出最大的曼哈顿距离。
【样例输入】
4 2
2 1
1 4
4 5
5 3
【样例输出】
6
【数据规模】
60%的数据,D<=2;
100%的数据,2<=N<=1000000,D<=4。
题解
自己先写出二维的情况
去掉绝对值 变成(?xi ?yi)-(?xj ?yj)
‘?’指不清它的符号
此时枚举这个符号就行了
最多4维 所以最大为2^4
可以把1看为正号 0看为符号
此时是一个d位的二进制数
从1枚举到2^d 把每个二进制数代入
求一个最小值 一个最大值
每一个代入得到的答案就是最大减去最小
所以在每个得到的答案中选一个最大的就行了
#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#define inf 0x7ffffffusing namespace std;int maxn=-inf,minn=inf;int n,d;int a[1000005][5];void solve(int x){ for(int i=1;i<=n;i++){ int tot=0; for(int j=1;j<=d;j++){ if((1<<j)&x) tot+=a[i][j]; else tot-=a[i][j]; } maxn=max(tot,maxn); minn=min(tot,minn); }}int main(){ freopen("jail.in","r",stdin); freopen("jail.out","w",stdout); int ans=-inf; scanf("%d%d",&n,&d); for(int i=1;i<=n;i++) for(int j=1;j<=d;j++) scanf("%d",&a[i][j]); for(int i=1;i<=(1<<d);i++){ maxn=-inf;minn=inf; solve(i); ans=max(ans,maxn-minn); } printf("%d",ans); return 0;}
- 2017.7 13 NOIP模拟赛
- 【集训】jzoj 2017.7.13 noip模拟赛A 总结
- [noip模拟2017.7.3]
- 2017.7.15 NOIP模拟
- 2015-08-13NOIP模拟赛
- noip模拟赛 双城记
- 【noip模拟赛】密码
- 10.10NOIP模拟赛
- 10.08NOIP模拟赛
- 10.11NOIP模拟赛
- 10.12NOIP模拟赛
- 10.13NOIP模拟赛
- 【NOIP模拟赛】小奇挖矿
- NOIP模拟赛--军训
- 【NOIP模拟赛】数列
- noip模拟赛day8
- 16.1117 NOIP 模拟赛
- [NOIP模拟赛]单词
- 12.8线程和信号
- Android利用阴影让标题栏出现层次感
- 深入理解three.js对svg的支持(二):SVGRenderer
- Java之数组
- 个人所得税计算
- 2017.7 13 NOIP模拟赛
- bzoj2190: [SDOI2008]仪仗队
- MUI前端框架轮播图片+九宫格(左右滑动)
- BZOJ 1054 [HAOI2008]移动玩具
- 初识线段树
- linux C学习之实现简单的web服务器
- MOOC清华《程序设计基础》第5章第1题:判断数列的对称性
- shell实现简单的进度条
- python3.6 杨辉三角 小白能懂