Codeforces Round #789 (Div. 2)
阿新 • • 發佈:2022-05-09
簽到題沒啥好說的
點選檢視程式碼
#include<bits/stdc++.h> using namespace std; #define lowbit(x) x&(-x) #define ll long long const int maxn=105; int T; int a[maxn]; void solve(); int main(){ cin>>T; while(T--)solve(); return 0; } void solve(){ int n; int res=0;cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; if(a[i]==0)res++; } if(res)cout<<n-res<<endl; else{ sort(a+1,a+1+n); bool pd=1; for(int i=1;i<=n;i++) if(a[i]==a[i-1]) pd=0; if(pd)cout<<n+1<<endl; else cout<<n<<endl; } }
好像可以貪心不過我一眼看去就直接寫了dp
dp[i][j][k] 其中j為0/1表示當前為‘1’還是‘0’ k為0/1表示當前狀態合法還是不合法
表示前i個 第i位置個為j 狀態為k
合法一定是由不合法轉移過來的 不合法只能從合法轉移過來
點選檢視程式碼
#include<bits/stdc++.h> using namespace std; #define lowbit(x) x&(-x) #define ll long long const int maxn=2e5+5; int dp[maxn][2][2];// [1][1]當前為1 合法 [1][0]當前為0 合法 [0][1] 當前為1 不合法 [0][0] 當前為0 不合法 char s[maxn]; int T; void solve(); int main(){ cin>>T; while(T--)solve(); return 0; } void solve(){ int n; cin>>n; scanf("%s",s+1); memset(dp,0x7f,sizeof(dp)); dp[0][0][0]=dp[0][1][0]=dp[0][1][1]=dp[0][0][1]=0; for(int i=1;i<=n;i++){ dp[i][1][1]=dp[i-1][1][0]+(s[i]=='0'); dp[i][0][1]=dp[i-1][0][0]+(s[i]=='1'); dp[i][1][0]=min(dp[i-1][0][1],dp[i-1][1][1])+(s[i]=='0'); dp[i][0][0]=min(dp[i-1][1][1],dp[i-1][0][1])+(s[i]=='1'); } cout<<min(dp[n][0][1],dp[n][1][1])<<endl; }
這個題就上一個題目的加強版 我們只需要在轉移的時候順便記錄一下就好
這個題要用雙線並行 卡常數 沒啥意思 我下面的程式碼TLE了
點選檢視程式碼
#include<bits/stdc++.h> using namespace std; #define lowbit(x) x&(-x) #define ll long long const int maxn=2e5+5; int dp[maxn][2][2],num[maxn][2][2]; // [1][1]當前為1 合法 [1][0]當前為0 合法 [0][1] 當前為1 不合法 [0][0] 當前為0 不合法 char s[maxn]; int T,res; void solve(); int main(){ scanf("%d",&T); while(T--)solve(); return 0; } void solve(){ int n; scanf("%d",&n); scanf("%s",s+1); memset(dp,0x7f,sizeof(dp)); memset(num,0,sizeof(num)); dp[0][0][0]=dp[0][1][0]=dp[0][1][1]=dp[0][0][1]=0; for(int i=1;i<=n;i++){ dp[i][1][1]=dp[i-1][1][0]+(s[i]=='0'); num[i][1][1]=num[i-1][1][0]; dp[i][0][1]=dp[i-1][0][0]+(s[i]=='1'); num[i][0][1]=num[i-1][0][0]; if(dp[i-1][0][1]<dp[i-1][1][1]) num[i][1][0]=num[i-1][0][1]+1,dp[i][1][0]=dp[i-1][0][1]+(s[i]=='0'); else num[i][1][0]=num[i-1][1][1],dp[i][1][0]=dp[i-1][1][1]+(s[i]=='0'); if(dp[i-1][1][1]<dp[i-1][0][1]) num[i][0][0]=num[i-1][1][1]+1,dp[i][0][0]=dp[i-1][1][1]+(s[i]=='1'); else num[i][0][0]=num[i-1][0][1],dp[i][0][0]=dp[i-1][0][1]+(s[i]=='1'); } if(dp[n][0][1]<dp[n][1][1]) res=num[n][0][1]; else res=num[n][1][1]; printf("%d %d\n",min(dp[n][0][1],dp[n][1][1]),res+1); }
開始我想差分樹狀陣列去維護 但是發現有一左一右兩個限制 應該是可以維護出來的 但是我不知道怎麼維護
像這種題其實就是先定一邊 再計算
考慮先列舉斷點i 穿過i的區間很好計算 但是沒有穿過的呢?
我們只要依次處理右邊為斷點i的就好
描述不好描述 程式碼一看就能明白 這個題的解題思路很牛逼
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=5e3+5;
int T;
ll dp[maxn],a[maxn],pre[maxn];
void solve();
int main(){
cin>>T;
while(T--)solve();
return 0;
}
void solve(){
int n;cin>>n;
ll res=0;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
for(int i=1;i<n;i++)
for(int j=i+1;j<=n;j++)
if(a[i]>a[j])dp[i]++;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++)
if(a[j]>a[i])dp[j]--;
pre[0]=0;
for(int j=1;j<i;j++)pre[j]=pre[j-1]+dp[j];
for(int j=1;j<i;j++)
if(a[j]<a[i])
res+=(pre[i-1]-pre[j]);
}
cout<<res<<endl;
}