5.6CF做題日記【Codeforces Round #787 (Div. 3)A~D】(虛擬場補題)
前言
前三個一小時做出來了,但是後面出去沒做了,後來d也是自己做的,加油
題目連結集合
Dashboard - Codeforces Round #787 (Div. 3) - Codeforces
A. Food for Animals
題意
給出 a b c x y,分別指給狗的食物數量,給貓的食物數量,給貓和狗都能吃的食物數量,狗應吃食物數量,貓應吃食物數量; 求貓和狗是否夠吃
分析
題不難, 但也容易出亂子,這裡我用的是看貓和狗需要在c食物裡拿多少,然後和c比較
程式碼
#include<iostream> usingnamespace std; int main(){ int a,b,c,x,y,n=0,t,j=0; cin>>t; while(t--) { cin>>a>>b>>c>>x>>y; if(a<x) n=x-a;//狗額外需要的 if(b<y) j=y-b;//貓額外需要的食物 if((n+j)<=c) cout<<"YES\n"; else cout<<"NO\n"; n=0,j=0; } }
B. Make It Increasing
題意
每次可以把一個數除2,下取整,問需要操作多少次才能使序列遞增(相鄰兩數可以相等)
分析
從後往前遍歷,如果大於後面的數字,就一直除,但是,如果前面儘量小的話,那最後的序列應該是0 1 2 3 4 5 6...... 也就是說滿足a[i]>=i-1 (i=1~n-1)
需要注意的是考慮除到0不能再除了,要不然會一直迴圈(超時警告)
AC程式碼
#include<bits/stdc++.h> using namespacestd; typedef long long LL; typedef pair<int,int> PII; const int N = 1e5+10; int a[50]; int main() { int t; scanf("%d", &t); while(t --) { int n; cin >> n; for(int i = 1; i <=n ;i ++) cin >> a[i]; bool f = 1; int times = 0; if(a[n]==0 && n!=1)f = 0; else for(int i= n-1; i >= 1; i --) { while(a[i]>=a[i+1]) a[i]/=2, times++; if(a[i]<i-1) { f=0; break; } } if(!f)cout << "-1\n"; else cout << times<<endl; } return 0; }
C. Detective Task
Problem - C - Codeforces 型別:模擬
題意
畫被偷走了,一共有一些人來依次看過畫,主人問他們你們來的時候畫還有沒有,只有拿畫人可以撒謊,求有幾個人是嫌疑人
每個人只有3種回答:
1:來的時候畫還在
0:來的時候畫不在
?:記不清了
資料範圍
t [1,1e4] s長度總和不大於2e5
分析
有幾種情況:(程式碼中有詳解)
全是0和?:那就第一個0和前面的問號是嫌疑人
全是1和?:那就最後一個1和後面的問號是嫌疑人
0和1都有出現:那就0和1之間是嫌疑人(包括0和1)
AC程式碼
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> PII; const int N = 1e5+10; int a[50]; int main() { int t; scanf("%d", &t); while(t --) { string s; cin >> s; int sum = 0, tem = 0, num1 = 0; bool f0 = 0, f1 = 0;//f0是說有沒有0出現, f1同理 for(int i = s.size()-1; i >= 0; i --) { if(f0 && f1)break; if(s[i]=='?') tem ++; if(s[i]=='1') f1=1, sum = tem;//把結果傳給sum else if(s[i]=='0') f0=1, tem=1;//開始計數 if(!f1) num1++; } if(f0 && f1) cout << sum+1<<endl; //正常0和1之間的個數(包括0 1) else if(f0) cout << tem<<endl; //0和前面的?的集合 else if(f1) cout << num1+1 <<endl; //1和後面?的集合 else cout << s.size()<<endl;//全程都是‘?’ } return 0; }
來了來了, 最有練程式碼的題來了
D. Vertical Paths
Problem - D - Codeforces 型別:樹,dfs
題意
給出一個樹,要把數劃分成儘量少的路,每一段路不能重複,輸出路的數量,以及每條路走過的點
分析
大致思路:其實程式碼是類似於連結串列的,但是是用vector和queue存的,然後一步步的dfs,但是有些東西還是要注意的(超時警告)
1. 不能有重複的路,每次的路清空,不要再留在隊裡了
2. 超記憶體的問題,開始開了倆vector套queue,其中一個作為輸出,一個是存子節點,後來是把存輸出的給直接輸出了,但是要提前知道有多少條路
每個父節點,都不用單獨開一條路,下面的子節點如果要開路會帶著他們,所以路的條數 = n - 父節點個數
AC程式碼
#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> PII; const int N = 2e5+10; int n, q[N], idx=0, coun=0; queue<int> v[N]; void dfs(int root, int q[]) { if(v[root].size()==0)//輸出 { cout <<idx<<endl; for(int i = 0; i < idx; i ++) cout << q[i]<< ' '; cout<<endl; idx=0; return; } while(v[root].size()) { int t = v[root].front(); v[root].pop(); q[idx++]=t; dfs(t,q); idx=0;//走過就清空 } } void init() { for(int i = 0; i<= n;i++) while(v[i].size()) v[i].pop(); idx=0; coun =0; } int main() { int t; scanf("%d", &t); while(t --) { init(); int root, x; cin >> n ; for(int i = 1; i <= n; i ++) { cin >> x; if(x!=i) { v[x].push(i); if(v[x].size()==0)//因為當x==i,v[x]裡並不會加元素,還是空 coun ++; } else root = i; } q[0]=root; idx=1; cout << n-coun <<endl; dfs(root,q); cout <<'\n'; } return 0; }