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
數學期望。
利用數學期望的線性性:期望的和等於和的期望。