[TOC] # 8/5 A - Environment-Friendly Travel ::: spoiler [連結](https://codeforces.com/gym/102501/problem/A) 找出路程低於B的情況下,排放最少co2的排放量。 ```cpp= #include<iostream> #include<Math.h> #include<vector> #include<set> using namespace std; #define mp make_pair typedef pair<int,pair<int,int>> PIII; #define F first #define S second struct Point { //cost是路程不是co2排放量 int x=-1,y=-1,cost=0; bool vis; vector<pair<int,int> > go_co2; }; int dis(Point a, Point b) { return ceil(sqrt(pow(a.x-b.x,2)+pow(a.y-b.y,2))); } int T,N,B,co2[101]; Point home,des,tans[10001]; //pq拿來做Dijkstra set<PIII> pq; vector<PIII> edge; int main() { cin.tie(0); ios_base::sync_with_stdio(false); cin>>home.x>>home.y; cin>>des.x>>des.y; cin>>B>>co2[0]>>T; for(int i=1;i<=T;i++) cin>>co2[i]; cin>>N; for(int i=0;i<N;i++) { int num; cin>>tans[i].x>>tans[i].y>>num; for(int j=0;j<num;j++) { int to,way; cin>>to>>way; //先把邊存起來,之後等座標位置輸入完後再順便算co2的排放量 edge.push_back(mp(co2[way],mp(i,to))); } } //我把第N個車站當目的地 tans[N].x=des.x; tans[N].y=des.y; //把紀錄的邊都放進去 for(PIII it:edge) { int cost=it.F,a=it.S.F,b=it.S.S; tans[a].go_co2.push_back(mp(b,cost*dis(tans[a],tans[b]))); tans[b].go_co2.push_back(mp(a,cost*dis(tans[a],tans[b]))); } //再給每個車站連一條開車到目的地的邊 for(int i=0;i<N;i++) { tans[i].go_co2.push_back(mp(N,co2[0]*dis(tans[i],tans[N]))); } //把從家裡開車到每個車站或目的地的路程放進pq,超過B就不放 for(int i=0;i<=N;i++) { int d=dis(home,tans[i]); if(d <= B) { pq.insert(mp(d*co2[0],mp(d,i))); } } //開始Dijkstra while(!pq.empty()) { //如果走到目的地 if(pq.begin()->S.S==N) { cout<<pq.begin()->F; return 0; } //<int,<int,int>> 是 <co2排放量,<路程,目前所在車站index>> int co2=pq.begin()->F,index=pq.begin()->S.S,d=pq.begin()->S.F; pq.erase(pq.begin()); //p是目前車站 Point &p=tans[index]; //如果之前曾經看過這個車站,代表之前的排放量較小,這時如果連路程都比之前多那就不用考慮 //如果路程較小,有可能排放量低的被路程太大給卡住,這時就可以排放量較大但是路程小的再考慮一次 if(p.vis && d>=p.cost) continue; //紀錄路程 p.cost=d; p.vis=true; for(auto i:p.go_co2) { int to=i.first,cost=i.second; int newd=d+dis(p,tans[to]), newco2=co2+cost; //如果條件不符,代表就算朝目的地直走也太遠,所以不用考慮, if(newd + dis(tans[to],des) <= B) { pq.insert(mp(newco2,mp(newd,to))); } } } //出來的話就是沒辦法走到 cout<<-1; return 0; } ``` ::: # 8/5 K - Birdwatching ::: spoiler [連結](https://codeforces.com/gym/102501/problem/K) 設點I能直接通往點T且沒有辦法不經過(I,T)邊而前往點T 找出所有I ```cpp= #include<iostream> #include<vector> using namespace std; struct Node { //back紀錄的是會通往此點的點index vector<int> back; //若circle為true則代表點有一環同時經過此點和點vis_by bool circle=false; int vis_by=-1; }node[100000]; int N,M,T; //用來記錄走過的點,方便設circle vector<int> through; //from是出發點,x是目前點 void dfs(int from,int x) { //當此點被走過且不是繞一個圈 if(from != x && node[x].vis_by!=-1) { int origin=node[x].vis_by; //當此點不是由此次的出發點經過,且經過的那點和這點有環 //就可以從點from到x再順著環到origin //其他情況代表此點被走過,不用再走 if(from!=origin && node[origin].vis_by==-1 && node[x].circle) { node[origin].vis_by=from; } else { return; } } //當繞了一個圈 if(from == x) { //畫環 for(int i:through) { node[i].circle=true; } return; }else { //代表出發點可以走到此點 node[x].vis_by=from; } for(int to:node[x].back) { //不用管T if(T == to) continue; through.push_back(to); dfs(from,to); through.pop_back(); } return; } int main() { cin>>N>>M>>T; for(int i=0;i<M;i++) { int from,to; cin>>from>>to; //倒過來存 node[to].back.push_back(from); } //從每個會走到T的點 for(int i:node[T].back) { //從每個會走到的點 for(int j:node[i].back) { //不用管T if(j==T) continue; through.clear(); dfs(i,j); } } vector<int> ans; for(int i:node[T].back) { //沒被走過的會保留初始值 if(node[i].vis_by==-1) ans.push_back(i); } cout<<ans.size()<<endl; for(int i:ans) cout<<i<<endl; return 0; } ``` ::: # 8/12 A. Find a Number ::: spoiler [連結](https://codeforces.com/contest/1070/problem/A) 找出可被d整除且位數總和為s的最小正整數 ```cpp= #include<iostream> #include<queue> using namespace std; //mod是當前數字%D的結果,cnt是位數和 struct Str{ int mod,cnt; string s; Str(int m,int n,string str) { mod=m; cnt=n; s=str; } }; int D,S; //用來確保較小的數字先出來 queue<Str> q; //因為較小的數會先考慮,所以之後出現的數如果mod和cnt都相同,那就不用考慮 bool visit[501][5001]; int main() { cin>>D>>S; //初始化 for(int i=0;i<=D;i++) { for(int j=0;j<=S;j++) { visit[i][j]=false; } } q.push(Str(0,0,"")); //如果可能性都考慮完了,就代表不可能存在,輸出-1 while(!q.empty()) { Str &x = q.front(); //條件成立 if(x.mod==0 && x.cnt==S) { cout<<x.s; return 0; } for(int i=0;i<=9;i++) { //因為要確保從小的開始考慮,所以新數字會放在個位 int cnt = x.cnt+i, mod = (x.mod*10+i)%D; //把不合條件或已經遇過的去掉 if(cnt <= S && !visit[mod][cnt]) { q.push(Str(mod,cnt,x.s+char('0'+i))); visit[mod][cnt]=true; } } q.pop(); } cout<<-1; return 0; } ``` ::: # 8/12 C. Cloud Computing ::: spoiler [連結](https://codeforces.com/contest/1070/problem/C) 給天數,需要的CPU數,方案數,找到最便宜且盡量買滿需求CPU的總花費 ```cpp= #include<iostream> #include<vector> #define ll long long int using namespace std; //其實也可以用pair<ll,ll> struct CPU{ ll price=0,num=0; CPU(){}; CPU(ll c,ll p) { price=p; num=c; } }; int N,K,M; //op的index是每個方案的開始提供日期,ed的index是結束日期+1 vector<CPU> op[1000002],ed[1000002]; //tree是紀錄總和的線段樹 CPU tree[4*1000002]; //輸出 ll ans=0; //l跟r代表價錢,把數量和價錢存入線段樹 void add(int index,int l,int r,ll c,ll p) { tree[index].num += c; tree[index].price += c * p; //l==r代表已經跑到最底了 if(l==r) return; int m=(l+r)/2; //p<=m代表要往左邊存,反之往右邊存 if(p<=m) { add(index*2,l,m,c,p); } else { add(index*2+1,m+1,r,c,p); } } //找到最便宜的價錢 void go(int index,int l,int r,ll need) { //需求大於供給,所以全買了 if(tree[index].num <= need) { ans += tree[index].price; return; } //l==r代表買不完r元的cpu,所以只買需要的量 if(l==r) { ans+= l*need; return; } int m=(l+r)/2; //先買便宜的 go(index*2, l, m, need); //不夠再買貴的 if(tree[index*2].num <need) { go(index*2+1, m+1, r, need - tree[index*2].num); } } int main() { cin>>N>>K>>M; for(int i=0;i<M;i++) { int from,to,c,p; cin>>from>>to>>c>>p; op[from].push_back(CPU(c,p)); ed[to+1].push_back(CPU(c,p)); } //依序計算每天的花費 for(int i=1;i<=N;i++) { //把每天新增可用的方案加進線段樹 for(CPU cpu:op[i]) add(1, 1, 1000000, cpu.num, cpu.price); //把每天過期不可用的方案移除線段樹 for(CPU cpu:ed[i]) add(1, 1, 1000000, -cpu.num, cpu.price); //計算花費 go(1,1,1000000,K); } cout<<ans; return 0; } ``` ::: # 8/12 E. Getting Deals Done ::: spoiler [連結](https://codeforces.com/contest/1070/problem/E) 每做m件任務需要休息前之前做的m件任務花費時間總和,最多只能花t時間 超過t時間時,接下來的任務都不需考慮 輸出x,d代表只選擇花費d時間以下(含)的任務做,可做x件,找出x最大的情況 ```cpp= #include<iostream> #include<set> #include<vector> #define ll long long int using namespace std; ll C,N,M,T,cases[200000]; set<int> st; vector<int> vec; pair<int,int> ans; //計算在d=x下的情況 bool check(int x) { // 累計時間 累計工作數 休息計數器 休息時間計數器 ll time=0,work=0,num=0,need_break=0; for(int i=0;i<N;i++) { //超過d不考慮 if(cases[i]>x) continue; //因為最後一次工作後可以不休息 //所以當成工作前才考慮休息就可以了 if(num==M) { time+=need_break; need_break=0; num=0; } need_break+=cases[i]; time+=cases[i]; num++; //時間超過時後面不考慮 if(time<=T) { work++; } else { break; } } //選較好的答案 if(ans.first < work) ans = make_pair(work,x); //如果時間用完代表d太大了,反之則太小 if(time>T) return false; else return true; } //二分搜 void two(int l, int r) { int m=(l+r)/2; //搜到底了 if(l==r) { //怕沒搜乾淨 check(vec[m]); return; } if(check(vec[m])) { two(m+1,r); } else { //感覺m-1也可以,只是到底的條件可能要改成r<=l two(l,m); } } int main() { ios::sync_with_stdio(0); cin.tie(0); cin>>C; while(C--) { cin>>N>>M>>T; ans=make_pair(-1,-1); vec.clear(); st.clear(); for(int i=0;i<N;i++) { cin>>cases[i]; //大於T的不可能做得完 if(cases[i] <= T) st.insert(cases[i]); } for(int i:st) vec.push_back(i); if(!vec.empty()) two(0,vec.size()-1); if(ans.first==0 || ans.first==-1) { //當-1或0時代表選1~T當d都只能完成0個任務 cout<<0<<" "<<T<<endl; } else { cout<<ans.first<<" "<<ans.second<<endl; } } return 0; } ``` ::: # 8/12 G. Monsters and Potions ::: spoiler [連結](https://codeforces.com/contest/1070/problem/G) 給一排橫向排列的格子,格子有空地、怪獸、恢復藥三種,其中英雄可能會在空地上 英雄血量小於0時,英雄死亡 求一個集合點,並且以特定順序移動英雄至集合點,使所有英雄不死亡並到達集合點 ```cpp= #include<iostream> #include<deque> using namespace std; int N,M,board[101]; //index是所在位置 first是hp second是英雄的編號 pair<int,int> hero[101]; //用來記錄命令順序 deque<int> ld,rd; int main() { cin>>N>>M; for(int i=0;i<=N;i++) hero[i]=make_pair(-1,-1); for(int i=1;i<=M;i++) { int p,h; cin>>p>>h; hero[p]=make_pair(h,i); } for(int i=1;i<=N;i++) { cin>>board[i]; } //l是最右邊的左側英雄能平安抵達的集合點,r是最左邊的右側 //mxhp代表當前可能最高血量 int l=-1,r=N+1,mxhp=-1; for(int i=1;i<=N;i++) { //代表這格有英雄 if(board[i] == 0 && hero[i].first != -1) { //讓血量高的先出動 if(mxhp < hero[i].first ) ld.push_front(hero[i].second); else ld.push_back(hero[i].second); //取血量最高者 mxhp = max(mxhp,hero[i].first); } //代表還沒找到第一個英雄 if(mxhp == -1) continue; if(board[i] != 0) { mxhp+=board[i]; //英雄死亡 if(mxhp < 0) { break; } } //代表走得到這一格 l=i; } mxhp=-1; for(int i=N;i>=0;i--) { if(board[i] == 0 && hero[i].first != -1) { if(mxhp < hero[i].first ) rd.push_front(hero[i].second); else rd.push_back(hero[i].second); mxhp = max(mxhp,hero[i].first); } if(mxhp == -1) continue; if(board[i] != 0) { mxhp+=board[i]; if(mxhp < 0) { break; } } r=i; } //如果左邊的極限和右邊的極限能夠相接,那就有解 if(r <= l+1) { cout<<l<<endl; bool vis[101]; for(int i=0;i<=M;i++) vis[i]=false; for(int i:ld) { vis[i]=true; cout<<i<<" "; } for(int i:rd) { //因為一位英雄只能移動一次 if(!vis[i]) cout<<i<<" "; } } else { cout<<-1; } return 0; } ``` ::: # 9/2 A. Augmented Reality Game ::: spoiler [連結](https://codeforces.com/gym/100257) 給N個點的鑰匙數量(鑰匙可建立一條與其他點的通道) 求最多可產生多少個三角形(三角形的邊不能重複使用,但是同樣的三角形可以有多個) ```cpp= #include<iostream> using namespace std; int N; int main() { cin>>N; //sum是鑰匙總數 mx是單點鑰匙的最大值 int sum=0,mx=-1; for(int i=0;i<N;i++) { int k; cin>>k; mx = max(mx,k); sum += k; } //此時無法組成三角形 if(N==1 || N==2) cout<<0; //因為每2 1 0個鑰匙可組一個三角形,所以檢查最多鑰匙的點能否用光鑰匙 else if(mx <= (sum-mx)*2) cout<<(sum/3); //用不完 else cout<<(sum-mx); return 0; } ``` ::: # 9/2 F. Four Ways to Travel ::: spoiler [連結](https://codeforces.com/gym/100257) 地上運輸(S)26元,地下運輸(U)28元, 90分鐘內無限地上運輸+1次地下運輸套餐44元 機器會自動查看90分鐘內的紀錄並在使用套餐能省錢時自動使用 求機器判斷所花的錢跟可能的最小值 ```cpp= #include<iostream> using namespace std; //d是用來dp的 ans1是機器的 ans2是最佳的 int N,d[60*24+1],keep[60*24],ans1=0,ans2; int main() { cin>>N; for(int i=0;i<60*24;i++) { keep[i] = -1; d[i] = 1e9; } d[60*24]=1e9; d[0]=0; for(int i=0;i<N;i++) { string s; cin>>s; //h是時 m是分 int h = stoi(s.substr(0,s.find(":"))), m = stoi(s.substr(s.find(":")+1,s.size())); cin>>s; //-1代表沒有 0代表地上 1代表地下 if(s=="S") keep[h*60+m] = 0; else if(s=="U") keep[h*60+m] = 1; } //use=-1代表無使用套餐,否則代表結束時間 int use = -1; //subway代表目前套餐有沒有搭過地下運輸 bool subway = false; for(int i=0;i<60*24;i++) { //套餐過期 if(use != -1 && use < i) { use = -1; subway = false; } //地上 if(keep[i] == 0) { if (use == -1) { bool y=false; for(int j=1;j<=90 && i+j<60*24;j++) { if(keep[i+j] != -1) y=true; } //用了會省錢的話就用 if(y) { ans1 += 44; use = i+90; } else ans1 += 26; } } else if(keep[i] == 1) { //還沒用套餐 //或套餐還有搭過地下運輸,代表套餐在此刻結束 if (use == -1 || subway) { bool y=false; for(int j=1;j<=90 && i+j<60*24;j++) { if(keep[i+j] == 1) break; else if(keep[i+j] == 0) y=true; } if(y) { ans1 += 44; use = i+90; subway = true; } else { ans1 += 28; } } else subway = true; } } //d[i]代表0~i-1的時間內最少花多少錢 for(int i=0;i<60*24;i++) { //因為是0~i-1,所以是i+91 //count是紀錄地下運輸次數 k是如果使用套餐可以更新到的最遠處 int k = min(60*24,i+91),count=0,add=0; for(int j=0;j<=90 && i+j<=60*24;j++) { if(keep[i+j] == 1) count++; if(count == 2) { k=i+j; break; } } if(keep[i] == 0) add=26; else if(keep[i] == 1) add=28; //不用套餐 d[i+1] = min(d[i+1],d[i]+add); //用套餐 d[k] = min(d[k],d[i]+44); } ans2 = d[60*24]; cout<<ans1<<" "<<ans2; return 0; } ``` ::: # 9/2 K. Top K Elements ::: spoiler [連結](https://codeforces.com/gym/100257) 根據xi = (A · xi−2 + B · xi−1 + C) mod 2^31取得所有x 然後輸出前K大的x ```cpp= #include<iostream> #include<algorithm> #include<vector> using namespace std; //MOD用來mod2^31 mask1用來取前16bits mask2用來取後16bits unsigned int MOD = (1LL<<31)-1,mask1 = (1LL<<32) - (1LL<<16),mask2 = (1LL<<16)-1; //front是第K個數的前16bits back是第K個數的後16bits //keep用來計數 unsigned int N,K,A,B,C,pre,prepre,keep[1<<16],front,back; vector<unsigned int> ans; int main() { cin>>N>>K>>prepre>>pre>>A>>B>>C; int p=pre,pp=prepre; for(int i=0;i<(1<<16);i++) keep[i]=0; for(int i=0;i<N;i++) { //if(i%1000000 == 0) cout<<i<<endl; unsigned int x = (A*pp) + (B*p) + C; x &= MOD; pp = p; p = x; x = (x & mask1) >> 16; keep[x]++; } int sum=0,tmp; //求第K個數的前16bits for(int i=(1<<16)-1;i>=0;i--) { sum += keep[i]; if(sum >= K) { front = i<<16; tmp = sum - keep[i]; break; } } p=pre,pp=prepre; for(int i=0;i<(1<<16);i++) keep[i]=0; for(int i=0;i<N;i++) { unsigned int x = (A*pp) + (B*p) + C; x &= MOD; pp = p; p = x; if((x & mask1) == front) keep[x & mask2]++; } sum=tmp; //求第K個數的後16bits for(int i=(1<<16)-1;i>=0;i--) { sum += keep[i]; if(sum >= K) { back = i; break; } } ////第K個數=front+back; p=pre,pp=prepre; for(int i=0;i<N;i++) { unsigned int x = (A*pp) + (B*p) + C; x &= MOD; pp = p; p = x; //大於的丟進去 if(x > front+back) ans.push_back(x); } //要排序 sort(ans.rbegin(),ans.rend()); for(int i:ans) cout<<i<<" "; //補上不夠的 for(int i=ans.size();i<K;i++) cout<<front+back<<" "; return 0; } ``` ::: # XX/XX XX ::: spoiler [連結]() ```cpp= ``` :::
{"metaMigratedAt":"2023-06-17T06:34:03.857Z","metaMigratedFrom":"Content","title":"8/5 A - Environment-Friendly Travel","breaks":true,"contributors":"[{\"id\":\"d6e0a1ed-c20a-4d54-a1e6-8e446b75271a\",\"add\":18358,\"del\":4778}]"}
Expand menu