水題,把a累加,然後向上取整(double)a/5,把b累加,然後向上取整(double)b/10,然後判斷a+b是不是大於n即可
#include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; int main(){ double a1,a2,a3; double b1,b2,b3; int n; cin >>a1 >> a2 >> a3 >>b1 >> b2 >> b3>> n; int cnt = ceil((a1+a2+a3)/5)+ceil((b1+b2+b3)/10); if(cnt > n) cout <<"NO"<<endl; else cout<<"YES"<<endl; }
題目的意思是:
給兩個字串s和t,對字串s可以進行下面操作(注意每種操作可以進行無限次)
- 刪除s的一個字元,如果只做這種操作,輸出automation
- 交換s的任意兩個字元,如果只做這種操作,輸出array
- 如果既要刪除又要交換,則輸出both
- 如果上面操作無法完成,則輸出need tree
解題思路:
(1)首先判斷s和t的長度,如果s的長度比t的長度小,則上面的操作都無法完成如果s的長度大於t的長度,則需要刪除字元
(2)將s中不屬於t內的字元刪除,這剩下的字元為str
(3)統計str和t中各自字串出現的次數,
如果中的字元不在str中,即strCnt.size() < tCnt.size(),則上面操作無法完成。
如果tCnt中某字元的個數大於strCnt的字元的個數,則上面的操作無法完成。
如果strCnt中存在字元的個數大於tcnt的相應字元的個數,則必須要刪除s的字元。
如果s的所有字元的個數和t的所有字元的個數相等,則只需要交換即可
(4)最後通過在str中使用兩個指標i,index,i指向str,index指向t,遍歷str,如果t[index]==str[i],則index++; 最後判斷index是否指向t的末尾,如果是,則只需要刪除字元即可,否則既要刪除又要交換字元。
#include <iostream> #include <vector> #include <algorithm> #include <string> #include <map> using namespace std; int main(){ string s,t; cin >>s >>t; bool needTree = false,automatonFlag = false; if(s.length() < t.length()) needTree = true; else if(s.length() >t.length()) automatonFlag = true; string str=""; for(int i = 0 ; i < s.length(); ++ i ){ if(t.find(s[i])!=string::npos) str+=s[i]; } map<char,int> strCnt,tCnt; for(int i = 0 ; i < str.length(); ++ i) strCnt[str[i]]++; for(int i = 0 ; i < t.length(); ++ i) tCnt[t[i]]++; if(strCnt.size()!=tCnt.size()) needTree = true; else{ for(map<char,int>::iterator iter = tCnt.begin(); iter!=tCnt.end(); iter++){ if(iter->second > strCnt[iter->first]) {needTree = true;break;} if(iter->second < strCnt[iter->first]) automatonFlag = true; } } if(needTree) cout<<"need tree"<<endl; else{ if(!automatonFlag) cout<<"array"<<endl; else{ int i = 0,index = 0; for(int i = 0 ; i < str.length() && index < t.length(); ++i){ if(t[index] == str[i]) index++; } if(index < t.length()) cout<<"both"<<endl; else cout<<"automaton"<<endl; } } }
題目的簡化意思是:
給你一個直方圖,每次只能用畫筆刷一行(注意是連在一起的)或者1豎,求至少要刷多少次能把這個直方圖刷完
解題思路是
每次取min(a1,a2,...an),然後水平刷min(a1,a2,...an)次,刷完後,相當於每個直方條少了ai-min(a1,a2....an)(i=0..n-1),這時候這些直方條就會被高度為0的直方條隔開,然後對每個部分,進行遞迴呼叫,算出次數,注意每次還要和right-left+1(相當於每直方條都刷一次)比較,然後取小值。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int solve(vector<int>& a,int left, int right){ if(right< left) return 0; int minv = *min_element(a.begin()+left,a.begin()+right+1); int res = minv, index = left; for(int i = left; i<=right; ++i) a[i]-=minv; for(int i = left; i<= right; ++ i){ if(a[i] == 0 ){ if(index < i) { res+=solve(a,index,i-1); } index = i+1; } } res+=solve(a,index,right); return min(res,right-left+1); } int main(){ int n; cin >> n ; vector<int> a(n,0); for(int i = 0 ; i < n; ++ i) cin >> a[i]; cout<<solve(a,0,n-1)<<endl; }
求二維陣列第k小值,用優先權佇列取每個元素的下面和右邊的元素插入佇列,結果超時。由於用優先權佇列其時間複雜度為klognm,而k<=nm則最壞時間複雜度是nmlog(nm),肯定超時
#include <iostream> #include <vector> #include <cmath> #include <queue> #include <functional> #define LL long long using namespace std; struct Point{ int row; int col; Point(int x=0, int y =0 ):row(x), col(y){} bool operator<(const Point& a) const{ return (LL)row*(LL)col > (LL)a.row*(LL)a.col; } }; int main(){ int n, m; LL k; cin >> n >> m >>k; vector<vector<bool> > visit(n+1,vector<bool>(m+1,false)); priority_queue<Point> que; que.push(Point(1,1)); visit[1][1] = true; LL res = 0; for(int i = 0 ; i <k; ++i){ Point tmp = que.top();que.pop(); res = (LL)tmp.row*(LL)tmp.col; Point a(tmp.row+1,tmp.col),b(tmp.row,tmp.col+1); if(a.row <= n && a.col<=m && !visit[a.row][a.col]){que.push(a);visit[a.row][a.col] = true;} if(b.row<=n && b.col<=m && !visit[b.row][b.col]) {que.push(b);visit[b.row][b.col] = true;} } cout<<res<<endl; }
現在利用二分搜尋。
假設對任意給一個數x,如何判斷nxm二維陣列中小於x的個數?
注意由於對第i行第j列的數是i*j,則j=x/i表示x在第i行的位置,也就是在該行第j列之前的位置都是小於x的
所以遍歷每行,然後累加min(m,x/i)即可,則即是小於x的個數。
#include <iostream> #include <vector> #include <algorithm> #define LL long long using namespace std; LL n,m,k; LL calc(LL x){ LL cnt = 0; for(LL i = 1; i <= n; ++ i ) cnt += min(m,x/i); return cnt; } int main(){ cin >> n >>m >>k; LL left = 1, right = n*m; while(left<=right){ LL mid = (left+right)/2; if(calc(mid) >=k) right = mid-1; else left = mid+1; } cout<<right+1<<endl; }
題目的意思:
給定一個整數X,X0=[X], Xi = [...]由Xi-1各個數的因子組成,求Xk,注意Xk中元素的個數最多為100000
解題思路:
本題先求出X1,即先求出X1的因子,然後對X每個因子進行深搜,直到k=0或者x=1,這樣求出每個因子的k,但深搜要注意剪枝,題目要求的Xk的因子數不多餘100000,故當搜尋的因子數到達100000,就把後面的因子剪掉。這樣可以避免超時
#include <iostream> #include <vector> #include <algorithm> #include <vector> #define LL long long using namespace std; LL limit = 1e5; vector<LL> divs,res; bool solve(LL x, LL k){ if(k == 0 || x == 1){ res.push_back(x); return res.size() >= limit; } for(int i = 0 ;i < divs.size(); ++ i){ if(divs[i] > x) break; if(x%divs[i] == 0){ if(solve(divs[i],k-1)) return true; } } return false; } int main(){ LL x,k; cin >> x >> k; for(LL i = 1; i*i <= x; ++ i){ if(x%i == 0){ divs.push_back(i); if(i*i != x) divs.push_back(x/i); } } sort(divs.begin(),divs.end()); solve(x,k); for(int i = 0 ; i < res.size(); ++ i){ if(i) cout<<" "; cout<<res[i]; } cout<<endl; return 0; }