Codeforces Round FF(Div. 2)
layout: post
title: Codeforces Round FF(Div. 2)
author: "luowentaoaa"
catalog: true
tags:
mathjax: true
- codeforces
- 線段樹
---
傳送門
A - DZY Loves Hash (簽到)
題意
給你一堆數,讓你mod一個值,然后問你第一個重復的值是再第幾次輸入,沒有重復就輸出-1
思路
簽到
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=1e5+50; const ll inf=0x3f3f3f3f3f3f3f3fLL; int a[maxn]; int ans=0; int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);int p,n;cin>>p>>n;for(int i=1;i<=n;i++){int k;cin>>k;k%=p;if(a[k]&&!ans){ans++;a[k]++;cout<<i<<endl;}a[k]++;}if(!ans)cout<<-1<<endl;return 0; }B - DZY Loves Strings (結論)
題意
給你一個字符串,你可以插入K個字符,每個字符都有一個權值W
使得f(s)最大
思路
做過的一題
因為字符個數沒有限制 所以直接無腦選最大的就行,然后就是考慮放在哪
如果把字符放前面那么原字符串的某些W值比較小的就會被推到后面使得答案變小
所以直接無腦放最后就行
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=1e5+50; const ll inf=0x3f3f3f3f3f3f3f3fLL; ll a[maxn]; int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);string s;cin>>s;int k;cin>>k;ll mx=0;ll ans=0;for(int i=0;i<26;i++){cin>>a[i];mx=max(mx,a[i]);}int len=s.size();for(int i=0;i<len;i++)ans+=(i+1LL)*a[s[i]-'a'];for(int i=1;i<=k;i++){ans+=(len+i*1LL)*mx;}cout<<ans;return 0; }C - DZY Loves Sequences (DP)
題意
給你一個數組,你可以改變一個位置的值,讓你找到一個最長的嚴格遞增的字串
輸出字串長度
思路
一開始直接DP 從頭開始做了設
\[ DP[i][0/1]表示到第I個數是否改變的最大值 并且用num[i][0/1]表示當前最后的值的答案 \]
然后果斷wa4
后面發現這樣只能保證前面的答案,但是如果后面的答案更優就會導致答案錯誤
所以我們 直接枚舉修改的位置然后判斷這個修改之后前后能否連接的答案是多少
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=1e5+50; const ll inf=0x3f3f3f3f3f3f3f3fLL; ll head[maxn]; ll tail[maxn]; ll a[maxn]; int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);int n;cin>>n;ll ans=0;for(int i=1;i<=n;i++){cin>>a[i];}for(int i=1;i<=n;i++){head[i]=1;if(a[i]>a[i-1])head[i]=head[i-1]+1;ans=max(ans,head[i]);if(i<n)ans=max(ans,head[i]+1);}for(int i=n;i>=1;i--){tail[i]=1;if(a[i]<a[i+1])tail[i]=tail[i+1]+1;ans=max(ans,tail[i]);if(i>1)ans=max(ans,tail[i]+1);}for(int i=2;i<n;i++){if(a[i-1]<a[i+1]-1)ans=max(head[i-1]+tail[i+1]+1,ans);}cout<<ans;return 0; }D - DZY Loves Modification( 優先隊列)
題意
給出一個N×M的矩陣,每次可以使得一行或者一列的所有元素減少P
然后答案加上刪去P之前的行(列)的值
讓你輸出必須操作K次之后的最大值
思路
首先行和列直接是有關聯的 不好處理
那么我們想想有沒有辦法分離行列之間的關系
我們發現如果我們刪去任意一行 這是每一列的值都會減少P
假設我們刪了q次行,那么對于后面的每一次刪除列的值都會減少q×P
所以行列之間的關系找到了
假設我們刪去了一列那么我們的答案為P+(刪去列獲得的值)-q×P
然后我們可以發現再固定刪去行的次數之后 每次刪去列的次數也固定了,
假設刪去K次行,那么之后的答案肯定會少去{q×P×(k-q)}
那么我們就只需要使得答案沒有刪去之前的答案最大就行了,
那么我們直接優先隊列亂搞就行
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const int maxn=1e6+50; const ll inf=0x3f3f3f3f3f3f3f3fLL; priority_queue<ll>prow,pcol; ll row[maxn],col[maxn]; ll a[1200][1200]; int main() {std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);int n,m,k,p;cin>>n>>m>>k>>p;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){cin>>a[i][j];}}for(int i=1;i<=n;i++){ll sum=0;for(int j=1;j<=m;j++){sum+=a[i][j];}prow.push(sum);}for(int i=1;i<=m;i++){ll sum=0;for(int j=1;j<=n;j++){sum+=a[j][i];}pcol.push(sum);}for(int i=1;i<=k;i++){row[i]=prow.top();prow.pop();prow.push(row[i]-1LL*m*p);row[i]+=row[i-1];}for(int i=1;i<=k;i++){col[i]=pcol.top();pcol.pop();pcol.push(col[i]-1LL*n*p);col[i]+=col[i-1];}ll ans=-inf;for(int i=0;i<=k;i++){ans=max(ans,row[i]+col[k-i]-1LL*(1LL*i*(k-i))*p);}cout<<ans;return 0; }E - DZY Loves Fibonacci Numbers(線段樹+斐波那契數列性質)
題意
給你一個數組,你有兩種操作,
1.把一個區間的值依次加上斐波那契數列的(i-start+1)項的值
2.輸出一個區間的合
思路
參考
首先討論斐波那契的性質
現在給出與本題有關的三個性質
1:若a,b滿足
\[ a_{n+2}=a_n+a_{n+1},b_{n+2}=b_n+b_{n+1} \]
若
\[ c_n=a_n+b_n \]
那么
\[ c_1=a_1+b_1,c_2=a_2+b_2,c_{n+2}=c_n+c_{n+1} \]
2:有通項公式
\[ a_n=F_{n-2}a_1+F_{n-1}a_2 \]
3:
有前綴和公示
\[ \sum_{i=1}^n a_i=a_{n+2}-a_2 \]
接下來證明時間
證明1:
\[ c_{n+2}=a_{n+2}+b_{n+2}=(a_n+a_{n+1})+(b_n+b_{n+1})=(a_n+b_n)+(a_{n+1}+b_{n+1})=c_n+c_{n+1} \]
證明2:
證明3:
\[ \begin{align} 2\Sigma_{i=1}^n a_i &= (a_1+a_2+...+a_n)+(a_1+a_2+...+a_n) \\ &=a_1+(a_1+a_2)+(a_2+a_3)+...+(a_{n-1}+a_n)+a_n \\ &=a_1+a_n+(a_3+a_4...+a_{n+1}) \\ &=(a_1+a_2+...+a_n)-a_2+a_n+a_{n+1} \\ &=\Sigma_{i=1}^n a_i+a_{n+2}-a_2 \\ \Sigma_{i=1}^n a_i &=a_{n+2}-a_2 \end{align} \]
所以我們可以記錄 通過前兩項的值就得出一段區間的和
通過性質1,我們知道 前兩項的答案 可以疊加;
通過性質2,我們可以O(1)地將前兩項的值下放;
通過性質3,我們可以O(1)地更新sum。
轉載于:https://www.cnblogs.com/luowentao/p/10450224.html
總結
以上是生活随笔為你收集整理的Codeforces Round FF(Div. 2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 求最大整数及其最小下标
- 下一篇: Blob