Codeforces Round #645 (Div. 2)
這一次的Div.2 大多數學思維。。
A. Park Lightingtime
https://codeforces.com/contest/1358/problem/A
題意:給一個n,m為邊的矩形,問最少的燈使得整個矩形照亮
思路:n * m 為總區域數一個燈最多能照亮兩塊區域,貪心做:每次都取照亮兩塊
#include<bits/stdc++.h> using namespace std; int main() { //freopen("in.txt","r",stdin); ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t, n, m; cin >> t; while (t--) { cin >> n >> m; cout << (n * m) / 2 + (n *m) % 2 << endl; } }
B. Maria Breaks the Self-isolation
https://codeforces.com/contest/1358/problem/B
題意:每個人有一個聚會值,要求來了的人數(算同時來的)>=聚會值,問最多能拉到多少人
思路:和之前的cfdiv2一道分配人,每個人有經驗值很像,那道題是sort後從前往後尺取,這道題sort就從後往前貪心
#include<iostream> #include<vector> #include<queue> #include<cstring> #include<algorithm> using namespace std; const int maxn=2e5+10; typedef long long LL; LL a[maxn]; int main() { LL t;cin>>t; while(t--) { LL n;cin>>n; for(LL i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+1+n); if(a[n]<=n) cout<<n+1<<endl; else { LL ans=1;LL sum=0; for(LL i=n;i>=1;i--) { if(a[i]<=i) { sum+=i;break; } } cout<<sum+1<<endl; } } return 0; }
C. Celex Update
https://codeforces.com/contest/1358/problem/C
題意:求(a,b)–>(c,d)的所有路徑總數中有多少路徑和不同的。
思路:考慮到xy變化,移動方法一定是 (x2 - x1) * (y2 - y1) ,然後發現自己到自己也是一種 故最後+1
#include<bits/stdc++.h> using namespace std; int main() { //freopen("in.txt","r",stdin); ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); long long x1, x2, y1, y2, t; cin >> t; while (t--) { cin >> x1 >> y1 >> x2 >> y2; cout << (x2 - x1) * (y2 - y1) + 1 << endl; } }
D. The Best Vacation
https://codeforces.com/contest/1358/problem/D
題意:每個月有d[i]天,有x天度假,要求連續,可以跨年,保證度假日子小於一整年。求d[i]求和最大的一段
思路:貪心+字首和+二分
貪心:
有這麼一段區間,貪A和貪B。
當bn(月的最後一天)>an-2,明顯可以得出B是最優的。
那麼當bn<an-2時,可以推出an-2>bn—->(等差遞增)an>bn,而且a月比b月長且最大值更大,所以在a月的末尾作為最後一天最優。
所以貪心把末尾的一天放到月末。
然後我們利用字首和統計每個月的天數和價值。然後列舉右端點,二分左端點,找到
sum[i]-sum[l]>x;且sum[i]-sum[l+1]<=x
那麼價值為summoney[i]-summoney[l+1];再算多出的x部分–知道x多出有多少天,然後在多出的區間裡用等差數列公式算出來。比如多出3天,就是那段區間的後三天的價值和。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 4e5 + 20;
typedef long long LL;
LL a[maxn];
LL sumday[maxn];
LL summoney[maxn];
int main(void)
{
LL n, x; cin >> n >> x;
for (LL i = 1; i <= n; i++)
{
cin >> a[i];
sumday[i] = sumday[i - 1] + a[i];
summoney[i] = summoney[i - 1] + (1 + a[i]) * a[i] / 2;
}
for (LL i = n + 1; i <= 2 * n; i++)
{
a[i] = a[i - n];
sumday[i] = sumday[i - 1] + a[i];
summoney[i] = summoney[i - 1] + (1 + a[i]) * a[i] / 2;
}
LL res = 0;
for (LL i = 1; i <= 2 * n; i++)
{
LL l = 0; LL r = i + 1;
//邊界處理
//找出第一個區間差大於等於x的位置
while (l < r)
{
LL mid = (l + r) >> 1;
if (sumday[i] - sumday[mid] <= x) r = mid;
else l = mid + 1;
}
if (l == 0 || r == i + 1) continue;
LL resday = x - (sumday[i] - sumday[l]);
LL sum = summoney[i] - summoney[l];
if (a[l] >= resday) sum += (2 * a[l] - resday + 1) * resday / 2;
res = max(res, sum);
}
cout << res << endl;
return 0;
}