atcoder beginner contest 251(D-E)

Tasks - Panasonic Programming Contest 2022(AtCoder Beginner Contest 251)\

D - At Most 3 (Contestant ver.) 

题意: 每次给定一个n,求出一个序列,保证每次可以从序列中选取最多三个数,来构成1-n中的所有数字,序列最大长度300。

题解; 可以直接求一个构成1-1e6的序列,开始时思考的二进制,但感觉很难控制在300以内,所以可以分成三份,每份100个,其实100个的话会有重复的。

三份分别是 *1 *100 *10000,至于为什么可以构成1e6内所有数字,首先*1可以构成1-100,*100的话,每一个数字都变成__00,后面两位在*1求出来了,*10000同理。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
signed main(){
  ll n;cin>>n;
  cout<<"300"<<endl;
  for(ll i=1;i<=100;i++) cout<<i<<" "<<i*100<<" "<<i*10000<<endl;
}

 

E - Takahashi and Animals

题意: 每次可以选择一个点,这个点可以把自身和下一点标记,第n个点标记自身和第一个点,每个点标记有权值,问最小权值。

题解: 每个点选与不选,经典dp,问题在于这是一个环形结构,所以需要对第一个进行处理,分成两种情况,从而变成链状结构。

  1. 第一个点标记,这样最后一个点就不被约束,可以标记,也可以不标记。
  2. 第一个点不标记,那么最后一个点一定要标记。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=3e5+50;
const ll mod=998244353;
const ll inf=1e18;
ll a[N],dp[N][2];
signed  main(){
  ios::sync_with_stdio(false);
  cin.tie(0);
  ll ans=inf;
  ll n;cin>>n;
  for(ll i=1;i<=n;i++) cin>>a[i];
  dp[1][1]=a[1];//第一个点标记
  dp[1][0]=inf;
  for(ll i=2;i<=n;i++){
    dp[i][0]=dp[i-1][1];
    dp[i][1]=min(dp[i-1][0],dp[i-1][1])+a[i];
  }
  ans=min(ans,min(dp[n][0],dp[n][1]));
  memset(dp,0,sizeof(dp));
  dp[1][1]=inf; // 第一个点不标记 
  dp[1][0]=0;
  for(ll i=2;i<=n;i++){
    dp[i][0]=dp[i-1][1];
    dp[i][1]=min(dp[i-1][0],dp[i-1][1])+a[i];
  }
  ans=min(ans,dp[n][1]);
  cout<<ans;
}

 

posted @ 2022-07-06 20:32  HHzp  阅读(40)  评论(0)    收藏  举报