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,问题在于这是一个环形结构,所以需要对第一个进行处理,分成两种情况,从而变成链状结构。
- 第一个点标记,这样最后一个点就不被约束,可以标记,也可以不标记。
- 第一个点不标记,那么最后一个点一定要标记。
代码:
#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; }