雷比較多,須要一個一個踩。node
考察點 : 簽到題,是否細心(就是看你可否跳過坑) 坑點 : 注意都用 long long 數據類型(兩個數相加 可能也會爆 int 哦,剛開始就 卡在這了)
Code:ios
#include <iostream> #include <algorithm> using namespace std; typedef long long LL; LL a,b,c,x,y,z; LL res = 0; int main(void) { scanf("%lld%lld%lld",&a,&b,&c); // long long scanf("%lld%lld%lld",&x,&y,&z); res += min(a,y) + min(b,z) + min(c,x); cout << res << endl; return 0; }
考察點 : 字符串,及特判,對某些名詞的概念理解 坑點 : 必定要認真讀題,認真讀題,題中是子串,而不是子序列,子串是連續的,因此 616必定是連續的,好比 61616就是 兩個,而不是三個,只統計616,不用統計61616,也不能隨意組合,由於是連續的。
Code :函數
#include <map> #include <set> #include <queue> #include <deque> #include <cmath> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; string str; int n; LL one,six; int main(void) { scanf("%d",&n); cin >> str; for(int i = 0; i < str.length(); i ++) { // 只須要判斷 6 和 1 的個數便可 if(str[i] == '1') one ++; if(str[i] == '6') six ++; } six --; if(one == 0 || six < 1) cout << 0 << endl; else cout << min(six,one); // 子串是連續的,子序列能夠是不連續的 return 0; }
考察點 : dp ,機率, 同餘定理,模運算下的意義
坑點 : long long ,模的數通常都比較大,因此用 long long 比較保險
最好 + 上一個 MOD 防止出現 負數ui
遇到 DP 就歇菜,只能慢慢啃了。 DP 最容易的是隻須要一個轉移方程,最艱難的就是找到這個轉移方程。(通常是題最後問的是什麼咱們就設什麼) 假設 DP[i][j] 表示前 i 道題中 剛好作對 j 道的機率是多少,下一步就會出現兩種狀況: 一、第 i 道是對的,那麼 dp[i][j] = dp[i - 1][j - 1] * p[i]; 二、第 i 道是錯的,那麼 dp[i][j] = dp[i - 1][j] * (1 - p[i]); // 1 - p[i] 是作錯的機率 因此 dp[i][j] = dp[i - 1][j - 1] * p[i] + dp[i - 1][j] * (1 - p[i]);
Code:spa
#include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int MOD = 1e9 + 7; const int maxn = 2020; LL dp[maxn][maxn],p[maxn]; int n; int main(void) { scanf("%d",&n); for(int i = 1; i <= n; i ++) { scanf("%lld",&p[i]); } dp[0][0] = 1; for(int i = 1; i <= n; i ++) { // 前 i 道中 0 道正確的機率也就是沒有正確的機率(初始化,爲後面作準備) dp[i][0] = dp[i - 1][0] * (MOD + 1 - p[i]) % MOD; // + 1是爲了防止取到負數 (同餘定理) } for(int i = 1; i <= n; i ++) { for(int j = 1; j <= i; j ++) { dp[i][j] =( (dp[i - 1][j - 1] * p[i]) % MOD + dp[i - 1][j] * (MOD + 1 - p[i]) ) % MOD; // 單個模跟 + 括號 模總體是不同的 } } for(int i = 0; i <= n; i ++ ) { cout << dp[n][i] << ' '; } return 0; }
考察點 : 數學知識,動手能力 坑點 : 多畫畫就都看出來了,三點共線的必定沒法組成三角形,須要咱們進行特判(太坑了) 平面內任意三個點均可以組成一個三角形,只有是線段是咱們纔會用三角形定理去判斷。
這道題都能看出來,但能作對仍是不太容易的,尤爲對於像我這種渣渣來講,就是動手能力太差,其實看到這道題就應該先想一想 有哪些地方須要特判的(三點共線卡了將近半個小時,最後仍是從別人那裏聽來的,太不容易了)。
Code :3d
#include <map> #include <set> #include <queue> #include <deque> #include <cmath> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 505; struct node { double x,y; } dot[maxn]; int n; double a[5]; double num(int x,int y) { return (dot[x].x - dot[y].x) * (dot[x].x - dot[y].x) + (dot[x].y - dot[y].y) * (dot[x].y - dot[y].y) ; } int main(void) { scanf("%d",&n); for(int i = 1; i <= n; i ++) { scanf("%lf%lf",&dot[i].x,&dot[i].y); } LL res = 0; for(int i = 1; i <= n; i ++) { for(int j = i + 1; j <= n; j ++) { for(int k = j + 1; k <= n; k ++) { if((dot[k].y - dot[i].y) * (dot[j].x-dot[i].x) - (dot[j].y-dot[i].y)*(dot[k].x-dot[i].x) == 0) continue; // 用斜率來判斷三點是否共線 a[0] = num(i,j),a[1] = num(i,k),a[2] = num(j,k); //鈍角三角形: 假設 C 是最長邊,需知足 A^2 + B^2 < C^2 或者一個角 > 90度 sort(a,a + 3); if(a[0] + a[1] < a[2]) res ++; } } } printf("%lld\n",res); return 0; }
考察點 :數論,思惟
坑點 : 不一樣的兩個數交換位置也算一組(哈哈哈哈哈,這也能夠,服了,仍是想的不夠周到)code
乍一看,數論呀,直接跳過,結束後看題解,真easy。(仍是能力不濟) 咱們須要將原來的式子簡化一下,而後縮減範圍,就像咱們以前學的,遇到根號開根號,而後觀察這個式子的性質。
Code:blog
#include <map> #include <set> #include <queue> #include <deque> #include <cmath> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; int n; vector<int>num; int main(void) { scanf("%d",&n); LL res = 0; for(int i = 1; i * i <= n; i ++) { if(i == sqrt(i * i)) { num.push_back(i * i); } } for(int i = 0; i < num.size(); i ++) { for(int j = 1; j * j <= num[i]; j ++) { if(num[i] % j == 0) { if(num[i] / j != j) res += 2; // i 和 j 位置不相等的時候互換位置也算,啊啊啊 else res ++; } } } cout << res << endl; return 0; }
考察點: 貪心(鄰項交換),排序
坑點 : 錯誤的貪心思想,哪一個屬性的值大就選哪一個,這個並非最優結果.
eg: a : 2 200
b : 1000 50
若是咱們按照上述貪心思想,先對 a 排序取最大的顯然不是最優的。排序
也有多是總體相乘再排序,這樣會獲得一個最優得結果)(最惋惜的是我前幾天剛作過一道相似得題目,可是當時沒有總結 慘痛得教訓,學到得知識必定要及時整理和複習)
#include <map> #include <set> #include <queue> #include <deque> #include <cmath> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 2e5 + 10; struct node { LL a,b,pos; }gooda[maxn]; int vis[maxn]; int n; bool cmp1(node a,node b) { return a.a > b.a; } int main(void) { scanf("%d",&n); for(int i = 1; i <= n; i ++) { scanf("%lld",&gooda[i].a); } for(int i = 1; i <= n; i ++) { scanf("%lld",&gooda[i].b); gooda[i].a += gooda[i].b; gooda[i].pos = i; } sort(gooda + 1,gooda + 1 + n,cmp1); vector<LL>a,b; for(int i = 1; i <= n; i ++) { if(i % 2 == 1) a.push_back(gooda[i].pos); else b.push_back(gooda[i].pos); } for(int i = 0; i < a.size(); i ++) { cout << a[i] << " "; } cout << endl; for(int i = 0; i < b.size(); i ++) { cout << b[i] << " "; } cout << endl; return 0; }
考察點 : 快速冪,取模 坑點 : 換幾個模試試 MOD 1e9 + 7 有可能過不了, MOD % 1e9 + 8 就過了(哈哈哈哈,服了)
這麼大次方,確定選 快速冪,又有這麼大的數,得取模呀(雖然題目中沒有這樣要求,可是咱們能夠這樣嘗試一下)
Code :
#include <map> #include <set> #include <queue> #include <deque> #include <cmath> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int MOD = 1e9 + 8; typedef long long LL; LL a,b,c,d,e,f,g; LL quick_mod(LL a,LL b) { LL res = 1; while(b) { if(b & 1) res = res % MOD * a % MOD; a = a % MOD * a % MOD; b >>= 1; } return res; } int main(void) { int t; scanf("%d",&t); while(t --) { scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&g); LL ans = quick_mod(a,d) % MOD + quick_mod(b,e) % MOD + quick_mod(c,f) % MOD ; if(ans % MOD == g % MOD) { cout << "Yes" << endl; } else { cout << "No" << endl; } } return 0; }
考察點 : DP,思惟,推理 坑點 : 遇到 DP 就涼涼
Code : 待補(目前看題解還沒搞透徹)
考察點 : Tree,位運算,思惟
坑點 : 能想到就完事了,去重
初看這道題,這不是最小生成樹的模板嗎,可是定睛一看,發現沒邊權呀,這不是歇菜了。 後來在一位大佬的指導下,終於將其看懂,理解,而且AC。 這道題仍是蠻有特色的 : 求 異或(二進制位下相同 取 0 不一樣取 1),並且仍是 lowbit(異或)下的最小值。 咱們知道兩個不一樣的數在二進制下必定存在某一位是不一樣的(一個是 0 ,一個是 1),那麼在咱們的全部數中,也 必定存在在更低的位置(靠右的)有兩個不一樣的二進制位,咱們將這兩個不一樣的二進制位取異或,獲得的必定是 1 , 再lowbit那麼這個確定就是這兩個點的之間的最小邊權(咱們說了是在最低的位置),而後咱們知道全部數均可以 經過二進制表示出來,那麼這個數的二進制位與最低位的同一個位置的數必定不是 0 就是 1 ,咱們知道最小邊 權的一端存在一個 0 ,另外一端存在一個 1,那麼咱們只要讓這個數的的該二進制位是 0 就和 1 相連,是 1 就和 0 相連,由於異或。到這裏,就都是最小邊權了,最後的最小花費就是 (m - 1) * 最小邊權。 lowbit(x) = x & (-x); lowbit () 取得的值 1,2,4,8........(因此最多隻須要枚舉30次)(能夠寫個數的二進制位模擬一下)
#include <map> #include <set> #include <queue> #include <deque> #include <cmath> #include <vector> #include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 2e5 + 10; int n,value; bool Exit[31][2]; set<int>sets; set<int>::iterator it; int main(void) { scanf("%d",&n); for(int i = 1; i <= n; i ++) { scanf("%d",&value); sets.insert(value); // 題中沒有說不會有重複的值,須要去重,這也是一個坑點 } for(it = sets.begin(); it != sets.end(); it ++) { // 將全部數的二進制位進行標記 for(int i = 0; i <= 30; i ++) { int value = *it; if((value >> i) & 1) Exit[i][1] = true; else Exit[i][0] = true; } } LL res = 0; for(int i = 0; i <= 30; i ++ ) { if(Exit[i][0] && Exit[i][1]) { // 尋找最小的異或的位置 res = (sets.size() - 1) * (1 << i); break; } } cout << res << endl; return 0; }
J :求函數
考察點 : 線段樹的基本操做
坑點 : 代碼比較長,注意細節
線段樹咱們確定要找到須要合併得東西,例如求區間和咱們須要父節點存儲得是兩個數得和,求區間最大值咱們須要 往上推送的是兩個數的最大值,那這個須要往上pushup的是啥呢 ? 咱們發現 : f(L) = kL + b 因此 f(L1) = f(f(L)) = k(k * L + b) + b = k * k * L + k * b + b; 因此咱們pushup 的應該是 k * k + k * b + b (K, b 都是已知的)(能夠分紅兩部分)
#include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> #define int long long using namespace std; const int maxn = 2e5 + 10; const int MOD = 1e9 + 7; typedef long long LL; struct node { int l,r,k,b; } tree[maxn << 2]; int a[maxn],b[maxn]; int n,m; int ans,res; signed main(void) { void build(int u,int l,int r); void update(int u,int x); void query(int u,int l,int r); scanf("%lld%lld",&n,&m); for(int i = 1; i <= n; i ++) { scanf("%lld",&a[i]); } for(int i = 1; i <= n; i ++) { scanf("%lld",&b[i]); } build(1,1,n); while(m --) { int op,pos,l,r; scanf("%lld",&op); if(op == 1) { scanf("%lld",&pos); update(1,pos); } else { ans = 0,res = 1; // 這裏咱們設置成全局變量,就不用最後去合併了,最好仍是合併吧,這樣寫總感受有點不妥 scanf("%lld%lld",&l,&r); query(1,l,r); cout << (ans + res) % MOD << endl; } } return 0; } void pushup(int u) { tree[u].k = (tree[u << 1].k * tree[u << 1 | 1].k) % MOD; tree[u].b = (tree[u << 1 | 1].k * tree[u << 1].b + tree[u << 1 | 1].b ) % MOD; return ; } void build(int u,int l,int r) { if(l == r) { tree[u].l = l; tree[u].r = r; tree[u].k = a[l]; tree[u].b = b[l]; return ; } tree[u].l = l; tree[u].r = r; int mid = l + r >> 1; build(u << 1,l,mid); build(u << 1 | 1,mid + 1,r); pushup(u); return ; } void update(int u,int x) { if(tree[u].l == tree[u].r) { scanf("%lld%lld",&tree[u].k,&tree[u].b); return ; } int mid = tree[u].l + tree[u].r >> 1; if(x <= mid) update(u << 1,x); else update(u << 1 | 1,x); pushup(u); } void query(int u,int l,int r) { if(tree[u].l >= l && tree[u].r <= r) { res = (res * tree[u].k) % MOD; ans = (ans * tree[u].k + tree[u].b) % MOD; return ; } int mid = tree[u].l + tree[u].r >> 1; if(l <= mid) query(u << 1,l,r); // 這裏判斷條件必定不要寫反,寫反可能會發生段錯誤,調了一個多小時,最後仍是對照着別人的纔看出來 if(r > mid) query(u << 1 | 1,l,r); return ; }