1. 程式人生 > >2017 11.6 NOIP模擬賽

2017 11.6 NOIP模擬賽

max 卡特蘭 push gist const span map ext 理學

1.數學老師的報復
(attack.pas/c/cpp)
【問題描述】
11 班數學大佬 YXN 又在上數學課的時候把班主任 MP6 的錯誤當眾挑出來了,MP6 再一
次感到很難堪,於是決定報復 YXN
MP6 對 YXN 說:給你一個函數 f(x),定義如下:
f ( 1 ) = 1
f ( 2 ) = 1
f ( n ) = ( A * f ( n - 1 ) + B * f ( n - 2 ) ) mod 7。
YXN 說這還不簡單,可以秒殺!
MP6 微微笑了笑說:n 等於 100 你算得出來,那 n 等於 2147483648 呢?
YXN 啞口無言,決定向信息組的你求助。由於這是你唯一一次可以在數學題上秒殺 YXN,

你決定好好把握這一次機會。


【輸入】
僅一行包含 3 個整數 A,B 和 n。
【輸出】
一個整數,即 f ( n ) 的值。
【輸入輸出樣例】

樣例 1 樣例 2
attack.in attack.out attack.in attack.out

1 1 3
2

1 2 10

5


【數據說明】


20%的數據, n≤1,000
50%的數據, n≤100,000,000
100%的數據,n≤2147,483,648

思路 :矩陣快速冪加速加速

   轉置矩陣為 A 1

         B 0

    跑快速冪就好了

    但是我一開始是騙分做的

    因為 7 是一個很小的數 它的循環節不會很長

    每次找出循環節的長度即可。

技術分享
 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 ll n,aa,bb;
 5 struct matrix{    
 6     ll a[2][2];    
 7     matrix(){memset(a,0,sizeof(a));}    
 8     matrix(ll b[2][2])    {for(int i=0;i<2;i++)for(int j=0;j<2;j++)a[i][j]=b[i][j];}    
9 matrix operator * (matrix b) 10 { 11 matrix ans; 12 for(int i=0;i<2;i++) 13 for(int j=0;j<2;j++) 14 for(int k=0;k<2;k++) 15 ans.a[i][j]=(ans.a[i][j]+a[i][k]*b.a[k][j])%7; 16 ans.a[0][0]%=7; 17 return ans; 18 } 19 }S,T; 20 21 inline ll read() 22 { 23 ll x=0,f=1;char c=getchar(); 24 while(c<0||c>9){if(c==-)f=-1;c=getchar();} 25 while(c>=0&&c<=9){x=x*10+c-0;c=getchar();} 26 return x*f; 27 } 28 29 int main() 30 { 31 freopen("attack.in","r",stdin); 32 freopen("attack.out","w",stdout); 33 while(scanf("%lld%lld%lld",&aa,&bb,&n)!=EOF) 34 { 35 n-=2; 36 if(n==-1) {printf("1");return 0;} 37 ll temp[2][2]={{aa,1},{bb,0}}; T=temp; 38 ll temp2[2][2]={{1,1},{0,0}}; S=temp2; 39 while(n) 40 { 41 if(n&1) S=S*T; 42 T=T*T; 43 n>>=1; 44 } 45 S.a[0][0]%=7; 46 printf("%lld",S.a[0][0]); 47 } 48 return 0; 49 }
矩陣 技術分享
 1 #include <cctype>
 2 #include <cstdio>
 3 
 4 const int MAXN = 100010;
 5 
 6 typedef long long LL;
 7 
 8 int A, B;
 9 
10 LL n;
11 
12 inline void read(int&x) {
13     int f = 1; register char c = getchar();
14     for(x = 0; !isdigit(c); c == -&&(f = -1), c=getchar());
15     for(; isdigit(c); x = x * 10 + c - 48, c = getchar());
16     x = x * f;
17 }
18 
19 inline void read(LL&x) {
20     int f = 1; register char c = getchar();
21     for(x = 0; !isdigit(c); c == -&&(f = -1), c=getchar());
22     for(; isdigit(c); x = x * 10 + c - 48, c = getchar());
23     x = x * f;
24 }
25 
26 namespace stepone {
27     int F[1010];
28     inline void vinlince() {
29         F[1] = 1; F[2] = 1;
30         for(int i = 3; i <= n; ++i)
31               F[i] = (A * F[i - 1] + B * F[i - 2]) % 7;
32         printf("%d\n", F[n]);
33         return;
34     }
35 }
36 
37 namespace steptwo {
38     int F[1010], pos;
39     inline void vinlince() {
40         if(A % 7 ==0) {
41             if(n >= 3) printf("0\n");
42             else printf("1\n");
43             return; 
44         }
45         F[1] = 1; F[2] = 1;
46         for(int i = 3; i <= 1010; ++i) {
47             F[i] = (A * F[i - 1] + B * F[i - 2]) % 7;
48             if(F[i] == 1) {
49                 pos = i;
50                 break;
51             }
52         }
53         pos -= 2; --n;
54         n %= pos;
55         if(n == 0) n = pos;
56         printf("%d\n", F[n + 1]);
57         return;
58     }
59 }
60 
61 namespace stepthree {
62     int F[1010], pos;
63     inline void hhh() {
64         F[1] = 1; F[2] = 1;
65         for(int i = 3; i <= 1010; ++i) {
66             F[i] = (A * F[i - 1] + B * F[i - 2]) % 7;
67             if(F[i] == 1 && F[i - 1] == 1) {
68                 pos = i - 1;
69                 break;
70             }
71         }
72         --pos;
73         n %= pos;
74         if(n == 0) n = pos;
75         printf("%d\n", F[n]);
76         return;
77     }
78 }
79 
80 int main(int argc,char**argv) {
81     freopen("attack.in", "r", stdin);
82     freopen("attack.out", "w", stdout);
83     
84     read(A), read(B), read(n);
85     if(n <= 1000) stepone::vinlince();
86     else if(B % 7 == 0) steptwo::vinlince();
87     else stepthree::hhh();
88     
89     return 0;
90 }
規律

2.物理和生物老師的戰爭
(fseq.pas/c/cpp)
【問題描述】
物。萬物也。牛為大物。牛為物之大者。故物從牛。與半同意。天地之數起於牽
牛。戴先生原象曰。牽牛為紀首。命曰星紀。自周而上。日月之行不起於;牽牛也。按許說
物從牛之故。又廣其義如此。故從牛。勿聲。文弗切。十五部。
總之,物理老師和生物老師因為“物”而吵了起來,物理老師認為,物理是萬物之
源, 而生物老師認為生物才是萬物之源。 所以物理學科帶頭人和生物學科帶頭人號召了所有
物理、生物老師,進行戰鬥。
戰鬥開始前他們需要排隊,有 n 個物理老師和 m 個生物老師站在一起排成一列,
過安檢進入打鬥場。物理老師是一個神奇的物種,他們十分嚴謹,在開始之前就分析過:如
果在任意某一個人往前數(包括這個人) ,生物老師的數量超過了物理老師,根據牛頓三大
定律以及開普勒三大定律,這樣風水是不太好的。這時候,物理老師就會引爆核彈。為了構
建社會主義和諧社會,你決定避免這一場核戰的發生。所以,請你計算不會引發核彈爆炸的
排隊方案的概率。 (排隊方案不同定義為當且僅當某一位老師不一樣,註意不是老師所教的
科目不一樣。eg:物 A 物 B,物 B 物 A,是不同的方案)


【輸入】
第一行,Test , 表示測試數據的組數。
每個數據 有兩個數 N,M


【 輸出】
對於每組數據,輸出一個實數(保留到小數點後 6 位,)
【輸入輸出樣例 1】


fseq.in fseq.out 樣例說明:
3
1 0
0 1
1 1
1.000000
0.000000
0.500000
第一行:只有一個物理老師,一種方案且可行
第二行:只有一個生物老師,一種方案且不可行
第三行:兩種方案 ① 理、生 可行
② 生、理 不可行 可行概率為 0.5


【數據範圍】
30%的數據:(Test<=10),(0<=N,M<=1000).
100%的數據:(Test<=9008 ),( 0<=N,M<=20000 ).

思路:卡特蘭數應用 組合數學 進棧為題

   大家 可以去 這裏看一下 講的聽好的

   方案數 為 C(m!, (n+m)!) - C((m-1)!, (n+m)!)

   可以化出 (m+n)!/m!*n! *(1-m/(n+1))

   整個式子表示可行方案數 那後面的不就是可行的概率了麽。。

技術分享
 1 #include <map>
 2 #include <cstdio>
 3 #include <cctype>
 4 #define min(x,y) ((x) < (y) ? (x) : (y))
 5 
 6 const int MAXN = 5010;
 7 
 8 int T, n, m;
 9 
10 inline void read(int&x) {
11     int f = 1; register char c = getchar();
12     for(x = 0; !isdigit(c); c == -&&(f = -1), c=getchar());
13     for(; isdigit(c); x = x * 10 + c - 48, c = getchar());
14     x = x * f;
15 }
16 
17 int main(int argc,char**argv) {
18     freopen("fseq.in", "r", stdin);
19     freopen("fseq.out", "w", stdout);
20 
21     read(T);
22     while(T--) {
23         read(n);read(m);
24         if(n < m) printf("0.000000\n");
25         else printf("%.6lf\n",1.0-(m*1.0/(n + 1.0)));
26     }
27     return 0;
28 }
代碼

3.化學競賽的大獎
(prize.pas/c/cpp)
【問題描述】


XYX 在 CChO(全國化學奧林匹克競賽)比賽中獲得了大獎,獎品是一張特殊的機票。
使用這張機票,可以在任意一個國家內的任意城市之間的免費飛行,只有跨國飛行時才
會有額外的費用。XYX 獲得了一張地圖,地圖上有城市之間的飛機航班和費用。已知從
每個城市出發能到達所有城市,兩個城市之間可能有不止一個航班。一個國家內的每兩
個城市之間一定有不止一條飛行路線, 而兩個國家的城市之間只 有一條飛行路線。 XYX
想知道, 從每個城市出發到額外費用最大的城市, 以便估算出出行的費用, 請你幫助他。
當然,你不能通過乘坐多次一個航班增加額外費用, 也就是必須沿費用最少的路線飛
行。
【輸入】


第一行,兩個整數 N,M,表示地圖上有 N 個城市,M 條航線。
接下來 M 行,每行三個整數 a,b,c,表示城市 a,b 之間有一條費用為 c 的航線。
【 輸出】

共 N 行,第 i 行為從城市 i 出發到達每個城市額外費用的最大值。


【輸入輸出樣例 1】
score.in score.out 樣例說明:
6 6
1 4 2
1 2 6
2 5 3
2 3 7
6 3 4
3 1 8
4
4
4
6
7
7
有四個國家,包含的城市分別為 {1,2,3},{4},{5},{6}。
從城市 1 出發到達城市 6,乘坐(1,3)(3,6)兩個航班費用最大,
(1,3)在國內為免費航班,(3,6)的費用為 4,所以從 1 出發的最
大費用為 4。


【數據範圍】
對於 40%的數據 1<=N<=1000,1<=M<=1000
對於 100%的數據 1<=N<=20000,1<=M<=200000

思路 :首先 Tarjan 縮點

    建新圖 新圖一定為 樹   

    求一點能到達的點的路徑權值和最大

    跑 三遍DFS 或 用樹形Dp即可

技術分享
  1 #include <vector>
  2 #include <cstdio>
  3 #include <cctype>
  4 #include <cstring>
  5 #define max(x,y) ((x) < (y) ? (y) : (x))
  6 #define min(x,y) ((x) < (y) ? (x) : (y))
  7 
  8 const int MAXN = 20010;
  9 
 10 int n, m, inr, top, tot;
 11 
 12 int dfn[MAXN], low[MAXN], stack[MAXN << 1], col[MAXN], x[200010], y[200010], z[200010];
 13 
 14 int q[MAXN<<2], dis[MAXN], _dis[MAXN];
 15 
 16 std::vector<int> Graph[MAXN];
 17 
 18 bool vis[MAXN];
 19 
 20 struct node {
 21     int to, val;
 22     node(){}
 23     node(int to, int val):to(to), val(val){}
 24 };
 25 
 26 std::vector<node> New[MAXN];
 27 
 28 inline void read(int&x) {
 29     int f = 1; register char c = getchar();
 30     for(x = 0; !isdigit(c); c == -&&(f = -1), c=getchar());
 31     for(; isdigit(c); x = x * 10 + c - 48, c = getchar());
 32     x = x * f;
 33 }
 34 
 35 namespace Tarjan {
 36     
 37     void tarjan(int u, int fa) {
 38         dfn[u] = low[u] = ++inr;
 39         stack[++top] = u;
 40         vis[u] = true;
 41         for(int i = 0; i <Graph[u].size(); ++i) {
 42             int v = Graph[u][i];
 43             if(v == fa) continue;
 44             if(!dfn[v]) {
 45                 tarjan(v, u);
 46                 low[u] = min(low[u], low[v]);
 47             }
 48             else if(vis[v]) low[u] = min(low[u], dfn[v]);
 49         }
 50     
 51         if(dfn[u] == low[u]) {
 52             ++tot;
 53             int t;
 54             do {
 55                 t = stack[top--];
 56                 vis[t] = false;
 57                 col[t] = tot;
 58             }while(u != t);
 59         }
 60         return;
 61     }
 62     
 63     void Pre() {
 64         for(int i = 1; i <= m; ++i) {
 65             read(x[i]); read(y[i]); read(z[i]);
 66             Graph[x[i]].push_back(y[i]);
 67             Graph[y[i]].push_back(x[i]);
 68         }
 69     
 70         for(int i = 1; i <= n; ++i)
 71           if(!dfn[i]) tarjan(i, -1);
 72         return;
 73     }
 74 }
 75 
 76 namespace _next {
 77     int Max, root;
 78     
 79     void DFS(int u,int fa) {
 80         for(int i = 0; i < New[u].size(); ++i) {
 81             int v = New[u][i].to;
 82             if(v == fa) continue;
 83             dis[v] = dis[u] + New[u][i].val;
 84             if(dis[v] > Max) Max = dis[v], root = v;
 85             DFS(v, u);
 86         } 
 87         return;
 88     }
 89     
 90     void _DFS(int u,int fa) {
 91         for(int i = 0; i < New[u].size(); ++i) {
 92             int v = New[u][i].to;
 93             if(v == fa) continue;
 94             _dis[v] = _dis[u] + New[u][i].val;
 95             _DFS(v, u);
 96         }
 97         return;
 98     }
 99     
100     void hhh() {
101         
102         for(int i = 1; i <= m; ++i) {
103             if(col[x[i]] != col[y[i]]) {
104                 New[col[x[i]]].push_back(node(col[y[i]], z[i]));
105                 New[col[y[i]]].push_back(node(col[x[i]], z[i]));
106             } 
107         }
108         
109         DFS(1,-1);
110         Max = 0;
111         memset(dis, 0, sizeof dis);
112         DFS(root, -1);
113         _DFS(root, -1);
114         
115         for(int i = 1; i <= n; ++i) 
116           printf("%d\n", max(dis[col[i]], _dis[col[i]]));
117         return;
118     }
119 }
120 
121 int main(int argc,char**argv) {
122     freopen("prize.in", "r", stdin);
123     freopen("prize.out", "w", stdout);
124     
125     read(n), read(m);
126     Tarjan::Pre();
127     _next::hhh();
128         
129     return 0;
130 }
代碼

2017 11.6 NOIP模擬賽