五校联考解题报告
Day 1(题目在这儿)
T1 骰子
题意:
有一个 的网络的左上角(1,1)有一个
有一个骰子上面为 1 ,下面为6 左面为 4,右面为 3,前面为 2,后面为 5),先从左滚
右然后滚下去滚到最左边…..,每次记最上边点数为每次得分,问滚完以后可以得多少分?
解:
开始定义shang=1,xia=6,zuo=4…
暴力:
对于 数据, 模拟在每个格子上的状态,数据可以到10000左右不会超时。
而每次滚动需要考虑三种操作。
① 向左滚
右变上,上变左,左变下,下变右。
LL solz() { LL temp=shang; shang=you;you=xia;xia=zuo;zuo=temp; return shang; }
② 向右滚
LL soly() { LL temp=shang; shang=zuo;zuo=xia;xia=you;you=temp; return shang; }
③ 向下滚
LL sold() { LL temp=shang; shang=hou;hou=xia;xia=qian;qian=temp; return shang; }
对于100%的数据,需要观察一下筛子滚动的价值规律。
骰子对面相加价值为7,滚动一周价值为14,我们可以直接考虑滚动一行可以滚动多少周那么可以直接 14,然后一行剩余的最多枚举3次,时间复杂度优秀。
/*************************** 一轮noip模拟考试 Day1 T1 --2018.8.26 ***************************/ #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; #define LL long long LL shang=1,xia=6,zuo=4,you=3,qian=2,hou=5; LL n,m,sum,ans; LL solz() { LL temp=shang; shang=you;you=xia;xia=zuo;zuo=temp; return shang; } LL soly() { LL temp=shang; shang=zuo;zuo=xia;xia=you;you=temp; return shang; } LL sold() { LL temp=shang; shang=hou;hou=xia;xia=qian;qian=temp; return shang; } int main() { // freopen("dice.in","r",stdin); // freopen("dice.out","w",stdout); scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) { ans+=(m/4)*14; if(i%2==1&&m%4!=0) { ans+=shang; for(int j=1;j<m%4;j++)ans+=soly(); } else if(m%4!=0) { ans+=shang; for(int j=1;j<m%4;j++)ans+=solz(); } sold(); } printf("%lld",ans); // fclose(stdin);fclose(stdout); }
T2 子序列
题意:
给定一个序列 .
求序列中有多少对三元组(I,j,k),满足 或者$a[i] \le a[j] \le a[k]$或者$a[k] \le a[j] \le a[i]$ 。
解:
对于20%枚举i,j,k即可。
对于50%, 处理某个数左边有多少大于它的数,有多少小于它的数,右边有多少…,然后枚举j点,所以每个点满足的三元组数量为
左边大于$a[j]$的个数$\times$右边小的个数+左边小的个数$\times$右边大的个数
/***************** 考场50分代码 ********************/ int main() { freopen("sub.in","r",stdin); freopen("sub.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(a[j]>a[i])big[i]++; if(a[j]<a[i])small[i]++; } } for(int i=1;i<=n;i++) { for(int j=i+1;j<=n;j++) { if(a[j]!=a[i]) { if(a[j]>a[i]&&big[j])ans+=big[j]; if(a[j]<a[i]&&small[j])ans+=small[j]; ans%=mod; } } } printf("%d",ans); fclose(stdin);fclose(stdout); }
对于100%的数据,则需要先离散化,用到了两个树状数组。
将复制离散化完的的数组排序,二分查找下标加到第一个树状数组里,区间[1,i]的和表示的为小于以i为下标的离散化数组中的数的个数,那么当枚举到i时,树状数组中区间[1,a[i]-1](a[i]表示在离散化序列中a[i]的位置)的和表示a[1--i]中小于a[i]的数字个数,总数为i-1个,那么小于等于a[i]的数字个数为树状数组中区间[1,a[i]]的和,那么大于a[i]的数的个数为i-1-query(1,a[i-1])。
这部分代码:
for(int i=1;i<=n;i++) { a[i]=lower_bound(tmp+1,tmp+1+n,a[i])-tmp; l[i]=query(small,a[i]-1); //比i小(左边) ll[i]=i-1-query(small,a[i]); add(small,a[i],1); }
同理处理右边的数,为了简便可以倒序枚举序列。
/************************ 一轮Noip模拟赛Day 1 T2 --8.26 树状数组模板见于最后 *************************/ #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> using namespace std; #define LL long long #define mod int(1e9+7) LL n,a[200010],big[200020],small[200010],ans; LL tmp[200020]; LL l[200020],r[200020],ll[200020],rr[200020]; int lowbit(int i){ return i & -i; } LL query(LL *c,LL i) { LL sum=0; while(i>0) { sum+=c[i]; i-=lowbit(i); } return sum; } LL add(LL *c,int i,LL val) { while(i<=n) { c[i]+=val; i+=lowbit(i); } } int main() { // freopen("sub.in","r",stdin); // freopen("sub.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); tmp[i]=a[i]; } sort(tmp+1,tmp+1+n); for(int i=1;i<=n;i++) { a[i]=lower_bound(tmp+1,tmp+1+n,a[i])-tmp; l[i]=query(small,a[i]-1); //比i小(左边) ll[i]=i-1-query(small,a[i]); add(small,a[i],1); } for(int i=n;i>=1;i--) { r[i]=query(big,a[i]-1); //右边比i小的。 rr[i]=n-i-query(big,a[i]); add(big,a[i],1); } for(int i=1;i<=n;i++) { ans+=(l[i]*rr[i])%mod; ans+=(ll[i]*r[i])%mod; ans%=mod; } printf("%lld\n",ans); // fclose(stdin);fclose(stdout); }
T3 平面图
尚不会做正解,暂时只会10分。
子任务1:暴力搜索。
子任务3:n为奇数答案为0,偶数答案为2(开long long)
65递推式:$$ans = ((pow((pow(n, 2) % HA - (3 * n - 3) % HA) % HA, m % HA) % HA + ((n - 1) % HA) * ( (pow(3 - n, m) % HA) + (pow((1 - n) % HA, m) % HA) ) % HA) % HA) + (pow(n, 2) % HA) - (3 * n - 1) % HA;$$
HA为%数。
Day 2 (here)
T1
题意:
给你n个区间,每次区间[l,r]内的数+1,求最大的点数是多少?
解:
对于30%数据,O(n)枚举区间每一个数每次+1,总复杂度O( )
对于另外20%, 离散化一下,枚举+1.
另外20% 据说是考虑不会离散化的学生。
对于100%,标程居然比暴力都好写。
离散化一下,每个区间的左端点处+1,r+1处-1,然后统计下前缀和,记录最大的答案。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; #define LL long long LL l[200010],r[200020],tmp[400010]; LL n,ans,MAX,k,sum[433330]; int main() { freopen("meizi.in","r",stdin); freopen("meizi.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld%lld",&l[i],&r[i]); tmp[i*2-1]=l[i],tmp[i*2]=r[i]; } sort(tmp+1,tmp+1+2*n); for(int i=1;i<=n;i++) { l[i]=lower_bound(tmp+1,tmp+1+2*n,l[i])-tmp; r[i]=lower_bound(tmp+1,tmp+1+2*n,r[i])-tmp; sum[l[i]]++;sum[r[i]+1]--; } for(int i=1;i<=2*n;i++) { sum[i]=sum[i-1]+sum[i]; ans=max(ans,sum[i]); } printf("%lld",ans); fclose(stdin);fclose(stdout); }
T2
[无显示]你网页炸了!
T3
数学期望。
利用数学期望的线性性:期望的和等于和的期望。
除特别注明外,本站所有文章均为Manjusaka丶梦寒原创,转载请注明来自出处