iwtgm-5

题目链接

A.

个数为1的数一定会产生贡献,记为x
个数为2的数一定不会产生贡献,直接全部放入集合a
个数>2的数可产生也可不产生贡献,记为y

分类讨论:
x>0:
x为偶数,那么a,b集合平分x,其他全部放入a集合(反正不会有贡献)
x为奇数,需要多一个y放入b,

x<0,全放入a集合
代码:

int cnt[110];
int a[110];
char c[110];
bool f[110];
map<int,char>mp;
void solve()
{
  int n;cin>>n;
  for(int i=1;i<=n;i++){
      cin>>a[i];
      cnt[a[i]]++;
  }
  int fix=0,change_able=0;
  for(int i=1;i<=100;i++){
      if(cnt[i]==1)fix++;
      else if(cnt[i]==2)continue;
      else if(cnt[i]>2)change_able++;
  }
  if(fix%2==0&&fix!=0){
      cout << "YES" << endl;
      int p=1;
      for(int i=1;i<=n;i++){
          if(cnt[a[i]]==1){
              if(p&1)c[i]='A';
              else c[i]='B';
              p++;
          }
      }
      for(int i=1;i<=n;i++){
          if(c[i]=='B')cout<<'B';
          else cout<<'A';
      }
  } else if(fix%2!=0&&fix!=0&&change_able){
      cout << "YES" << endl;
      int p=1;
      for(int i=1;i<=n;i++){
          if(cnt[a[i]]==1){
              if(p&1)c[i]='A';
              else c[i]='B';
              p++;
          }
      }
      for(int i=1;i<=n;i++){
          if(cnt[a[i]]>2){
              c[i]='B';break;
          }
      }
      for(int i=1;i<=n;i++){
          if(c[i]=='B')cout<<'B';
          else cout<<'A';
      }
  } else if(fix==0) {
        cout << "YES" << endl;
        for(int i=1;i<=n;i++)cout<<'A';
    }else cout<<"NO";
}

C.

先考虑如何求最大连续子序列和

int n;
int a[N],dp[N];
void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    int ans=0;
    for(int i=1;i<=n;i++){
        dp[i]=max(a[i],dp[i-1]+a[i]);//dp[i]表示当前数一定要取(要么自己是头,要么接在上一个后面)
        ans=max(ans,dp[i]);//有可能不要当前数是最优,所以要每次取最大值
    }
    cout<<ans;
}

dp[i][]表示一定要取当前数
现在是加了状态,
3种:
dp[i][0]表示到目前是还没用魔法的,当前数无魔法
dp[i][1]表示到目前正在用魔法,当前数有魔法
dp[i][2]表示魔法已经用完了,当前数无魔法

int n;
ll x;
ll a[N],dp[N][3];
void solve()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)cin>>a[i];
    ll ans=0;
    for(int i=1;i<=n;i++){
        dp[i][0]=max({a[i],dp[i-1][0]+a[i]});//自己是头或者接到前面
        dp[i][1]=max({dp[i-1][0]+a[i]*x,dp[i-1][1]+a[i]*x,a[i]*x});//前一个数没用魔法或者用魔法加上当前数用魔法,或者自己用魔法当头
        dp[i][2]=max({dp[i-1][1]+a[i],dp[i-1][2]+a[i],a[i]});//前一个数用魔法或用完魔法加上当前数,或者自己当头
        ans=max({ans,dp[i][0],dp[i][1],dp[i][2]});//同样有可能不要当前数更优,每次都要比较
    }
    cout<<ans;
}

更简便的:

int n;
ll x;
ll a[N],dp[N][5];//dp[i][]表示一定要取当前数
void solve()
{
    cin>>n>>x;
    for(int i=1;i<=n;i++)cin>>a[i];
    ll ans=0;
    for(int i=1;i<=n;i++){
        dp[i][0]=max(dp[i-1][0]+a[i],0ll);//因为子序列可以为空,所以当前数是负数的话直接置0更优,和接到前面比较(前面>=0)
        dp[i][1]=max(dp[i][0],dp[i-1][1]+a[i]*x);//此时dp[i][1]和dp[i][0]比较,只有dp[i-1][1]是因为上一次的dp[i][1]和dp[i][0]已经比过了,也就是说此时的dp[i-1][1]中的数是上一次的dp[i][1]和dp[i][0]的较大值
        dp[i][2]=max(dp[i][1],dp[i-1][2]+a[i]);//同上理
        ans=max(ans,dp[i][2]);//同样可能不取当前数会更优,所以每次都要比较
    }
    cout<<ans;
}
posted @ 2023-11-02 13:22  WW爆米花  阅读(5)  评论(0编辑  收藏  举报