題目描述:給出課程安排,打印一個課程表。node
solution
暴力模擬。c++
題目描述:給定一個數\(n\),找出一個序列\(a_i\)知足\(\forall i \in [2, n], \sum_{j=1}^{j \leq i} a_j\) 有\(a_i\)個約數。函數
solution
暴力搜索,發現和不會超過\(2 \times 10^6\), 數字不會超過\(200\),並且直接搜索便可很快求出答案。this
時間複雜度:\(O(能過)\)spa
題目描述:求出從\(A\)年到\(B\)年中有\(1\)~\(12\)個黑色星期五的分別有多少年。3d
solution
顯然有循環,模擬一下發現2800年左右有循環,所以只須要求出循環中每年有多少個黑色星期五,而後求答案,求一下前綴和便可。code
時間複雜度:\(O(2800 \times 12)\)blog
題目描述:給出\(n\)個杯子,每一個杯子有一升的水,每次從一個杯子向另外一個杯子倒水,使得後一個杯子的水變成原來的兩倍,求出一種操做方案,使得最終有一個杯子有\(m\)升水,或無解。排序
solution
不會,原本想着好像二分那樣弄就行,但發現會有副產品利用的狀況,並且狀況有些複雜。ip
題目描述:給定空間中的兩條線段,問是否存在一條直線,使得一條線段繞直線轉某個角度便可獲得另外一條直線,求出這條直線和對應的角度。
solution
不會
題目描述:有兩個\(v(t)\)函數\(v_1, v_2\),這兩個函數都是折線函數,令\(h(t)=max(v_1(t), v_2(t)), g(t)=min(v_1(t), v_2(t))\),給出\(h(t), g(t)\)的起點、終點、轉折點,求出\(v_1(t), v_2(t)\),使得兩個函數所表明的位移相等。\(v_1, v_2\)重合點不超過\(30\)個。
solution
求出全部的重合點,假設開始時\(v_1=h, v_2=g\),而只有遇到重合點的時候,\(v_1, v_2\)纔有可能交換,即重合點將函數分紅了若干段,每一段中的函數不能相交,所以能夠分開先後兩個部分進行搜索,而後判斷是否存在一種方案使得合起來的位移等於總位移的一半。
注意:有可能\(h(t1) \neq g(t1)\),但\(v_1(t1) = v_2(t1)\)
時間複雜度:\(O(2 \times 2^{15})\)
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn=int(2e6)+100; int T, n, m; pair<int, int> h[maxn], g[maxn], tmp[maxn]; vector< pair<int, int> > v1, v2, cp; map<LL, int> cnt; LL sumh[maxn], sumg[maxn]; int block; bool vis[maxn]; void read() { scanf("%d", &T); scanf("%d", &n); for (int i=1; i<=n; ++i) scanf("%d%d" , &h[i].first, &h[i].second); scanf("%d", &m); for (int i=1; i<=m; ++i) scanf("%d%d", &g[i].first, &g[i].second); } void crosspoint() { for (int i=1; i<=n; ++i) tmp[i]=h[i]; int tmpn=n; n=1; for (int i=2; i<=tmpn; ++i) for (int j=tmp[i-1].first+1; j<=tmp[i].first; ++j) if (LL(j-tmp[i-1].first)*(tmp[i].second-tmp[i-1].second)%(tmp[i].first-tmp[i-1].first)==0) h[++n]=make_pair(j, LL(j-tmp[i-1].first)*(tmp[i].second-tmp[i-1].second)/(tmp[i].first-tmp[i-1].first)+tmp[i-1].second); /* puts("h:"); for (int i=1; i<=n; ++i) printf("%d %d\n", h[i].first, h[i].second); */ for (int i=1; i<=m; ++i) tmp[i]=g[i]; int tmpm=m; m=1; for (int i=2; i<=tmpm; ++i) for (int j=tmp[i-1].first+1; j<=tmp[i].first; ++j) if (LL(j-tmp[i-1].first)*(tmp[i].second-tmp[i-1].second)%(tmp[i].first-tmp[i-1].first)==0) g[++m]=make_pair(j, LL(j-tmp[i-1].first)*(tmp[i].second-tmp[i-1].second)/(tmp[i].first-tmp[i-1].first)+tmp[i-1].second); /* puts("g:"); for (int i=1; i<=m; ++i) printf("%d %d\n", g[i].first, g[i].second); */ for (int i=1, j=1; i<=n && j<=m; ++i) { while (j<=m && g[j].first<h[i].first) ++j; if (j>m) continue; if (h[i].first==g[j].first && h[i].second==g[j].second) cp.push_back(h[i]); } if (h[n].second!=g[m].second) cp.push_back(h[n]); /* puts("cp:"); for (auto &i:cp) printf("%d %d\n", i.first, i.second); */ } void calc_sum() { block=cp.size(); LL s=0; for (int i=2, j=0; i<=n; ++i) { while (j<cp.size() && cp[j].first<h[i].first) ++j; s+=LL(h[i-1].second+h[i].second)*(h[i].first-h[i-1].first); if (j>=cp.size()) continue; if (cp[j].first==h[i].first) sumh[j]=s, s=0; } s=0; for (int i=2, j=0; i<=m; ++i) { while (j<cp.size() && cp[j].first<g[i].first) ++j; s+=LL(g[i-1].second+g[i].second)*(g[i].first-g[i-1].first); if (j>=cp.size()) continue; if (cp[j].first==g[i].first) sumg[j]=s, s=0; } /* for (int i=0; i<block; ++i) printf("%lld ", sumh[i]); for (int i=0; i<block; ++i) printf("%lld ", sumg[i]); */ } inline LL det(pair<int, int> b, pair<int, int> c, pair<int, int> o) { return (b.first-o.first)*(c.second-o.second)-(b.second-o.second)*(c.first-o.first); } void print(LL sett) { for (int i=0, j=1, k=1; i<block; ++i) { if (sett>>i & 1) { while (j<=n && h[j].first<=cp[i].first) v1.push_back(h[j++]); while (k<=m && g[k].first<=cp[i].first) v2.push_back(g[k++]); } else { while (j<=n && h[j].first<=cp[i].first) v2.push_back(h[j++]); while (k<=m && g[k].first<=cp[i].first) v1.push_back(g[k++]); } } for (int i=0; i<v1.size(); ++i) vis[i]=true; for (int i=2; i<v1.size(); ++i) if (det(v1[i-2], v1[i-1], v1[i])==0) vis[i-1]=false; int ans=0; for (int i=0; i<v1.size(); ++i) ans+=vis[i]; printf("%d\n", ans); for (int i=0; i<v1.size(); ++i) if (vis[i]) printf("%d %d\n", v1[i].first, v1[i].second); for (int i=0; i<v2.size(); ++i) vis[i]=true; for (int i=2; i<v2.size(); ++i) if (det(v2[i-2], v2[i-1], v2[i])==0) vis[i-1]=false; ans=0; for (int i=0; i<v2.size(); ++i) ans+=vis[i]; printf("%d\n", ans); for (int i=0; i<v2.size(); ++i) if (vis[i]) printf("%d %d\n", v2[i].first, v2[i].second); } void solve() { crosspoint(); calc_sum(); LL total=0; for (int i=0; i<block; ++i) total+=sumh[i]+sumg[i]; total/=2; for (int i=0; i<1<<(block/2); ++i) { LL s=0; for (int j=0; j<block/2; ++j) if (i>>j & 1) s+=sumh[j]; else s+=sumg[j]; cnt[s]=i; } for (int i=0; i<1<<(block-block/2); ++i) { LL s=0; for (int j=0; j<block-block/2; ++j) if (i>>j & 1) s+=sumh[block/2+j]; else s+=sumg[block/2+j]; if (cnt.count(total-s)) { print(cnt[total-s]|(i<<(block/2))); return; } } } int main() { read(); solve(); return 0; }
題目描述:給定一個數字\(n\),將\(1\)到\(n\)從新排序:按各個位的數字的和從小到大排,相同的按預案數字從小到大排,問排序後的位置與原數字同樣的數有多少個。
solution
先作一個數位\(dp\),求出各個位的數字的和各有多少個,而後按這個進行分組,每一組最多隻有可能有一個數字的位置與原數字的位置相同,這是由於在同一組中,相鄰的數字的差事大於\(1\)的,所以不可能有兩個數字的位置與原位置相同,若是有,那麼這兩個位置之間的數字的差必須都是\(1\)。
若是用新數列減去舊數列,則在同一組中,獲得的數列是遞增的,而咱們要找的是是否存在一個等於零的位置,若是存在,則答案加一。這裏能夠用二分,每次二分用數位\(dp\)求出和與當前組的和同樣的,小於等於某個數的數字有多少個,就能夠判斷是否存在。
時間複雜度:\(O(81 \times log(10^9) \times 9*10*81)\)
題目描述:在平面上找出\(16\)個點,而後構成一個平面圖,使得該圖中的簡單環超過\(3\times10^5\)個。
solution
直接上圖。
題目描述:給出一個圖,\(n\)個點,\(m\)條邊,選擇一些邊,使得構成一顆生成樹,並且選擇的邊的權值的最大值與最小值的差最小,輸出方案。
solution
用\(LCT\)維護生成樹,將邊從小到大排序,而後逐條邊添加進去,每次添加後把環裏面的最小邊刪掉,更新答案。
時間複雜度:\(O(nlogn)\)
#include <bits/stdc++.h> using namespace std; const int maxn=int(5e4)+100; const int inf=0x7fffffff; struct node { node *son[2], *fa; node *maxid; int value, num; bool reverse; node() { son[0]=son[1]=fa=NULL; maxid=NULL; value=inf; num=0; reverse=false; } void update() { maxid=this; if (son[0] && son[0]->maxid->value<maxid->value) maxid=son[0]->maxid; if (son[1] && son[1]->maxid->value<maxid->value) maxid=son[1]->maxid; } void down() { if (!reverse) return; if (son[0]) { son[0]->reverse^=1; swap(son[0]->son[0], son[0]->son[1]); } if (son[1]) { son[1]->reverse^=1; swap(son[1]->son[0], son[1]->son[1]); } reverse=false; } void rotate(int id) { node *y=fa; node *z=y->fa; fa=z; if (z && (z->son[0]==y || z->son[1]==y)) z->son[z->son[1]==y]=this; y->son[id]=son[id^1]; if (son[id^1]) son[id^1]->fa=y; son[id^1]=y; y->fa=this; y->update(); update(); } void splay() { node *x=this; while (x->fa && (x->fa->son[0]==x || x->fa->son[1]==x)) { node *y=x->fa; node *z=y->fa; if (z && (z->son[0]==y || z->son[1]==y)) z->down(); y->down(); x->down(); if (!z || (z->son[0]!=y && z->son[1]!=y)) x->rotate(y->son[1]==x); else { bool L=z->son[1]==y, R=y->son[1]==x; if (L^R) x->rotate(R), x->rotate(L); else y->rotate(L), x->rotate(R); } } x->down(); x->update(); } node *expose() { node *x=this; node *y=NULL; for (; x!=NULL; y=x, x=x->fa) { x->splay(); x->son[1]=y; x->update(); } return y; } node *askroot() { node *x=expose(); while (x->son[0]) x=x->son[0]; x->splay(); return x; } void evert() { expose(); splay(); reverse=true; swap(son[0], son[1]); } void cut(node *x, node *y) { x->evert(); y->expose(); splay(); x->fa=y->fa=NULL; } void clear() { son[0]=son[1]=fa=NULL; maxid=NULL; value=inf; num=0; reverse=false; } }; struct LINK { int x, y, dis; int num; bool operator < (const LINK b) const { return dis<b.dis; } }; int n, m; LINK edge[maxn]; node tree[maxn*2]; set< pair<int, int> > len; bool vis[maxn]; void read() { scanf("%d%d", &n, &m); for (int i=1; i<=m; ++i) { edge[i].num=i; scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].dis); } } node *askmin(node *x, node *y) { x->evert(); y->expose(); x->splay(); return x->maxid; } void connect(node *x, node *y, int v, int idx) { node *z=tree+n+idx; z->value=v; z->num=idx; z->fa=x; y->evert(); y->fa=z; } void solve() { sort(edge+1, edge+1+m); int block=n; int minnum=inf; int ans; for (int i=1; i<=m; ++i) { node *u=tree+edge[i].x; node *v=tree+edge[i].y; len.insert(make_pair(edge[i].dis, i)); if (u->askroot()!=v->askroot()) connect(u, v, edge[i].dis, i), block--; else { node *x=askmin(u, v); len.erase(make_pair(x->value, x->num)); x->cut(tree+edge[x->num].x, tree+edge[x->num].y); connect(u, v, edge[i].dis, i); } if (block!=1) continue; int tmp=len.begin()->first; if (edge[i].dis-tmp<minnum) { minnum=edge[i].dis-tmp; ans=i; } } for (int i=1; i<=n+m; ++i) (tree+i)->clear(); for (int i=1; i<=ans; ++i) { node *u=tree+edge[i].x; node *v=tree+edge[i].y; vis[i]=true; if (u->askroot()!=v->askroot()) connect(u, v, edge[i].dis, i), block--; else { node *x=askmin(u, v); x->cut(tree+edge[x->num].x, tree+edge[x->num].y); vis[x->num]=false; connect(u, v, edge[i].dis, i); } } for (int i=1; i<=m; ++i) if (vis[i]) printf("%d ", edge[i].num); } int main() { read(); solve(); return 0; }
solution 按題目說的作。