首页 > 其他分享 >PKUSC2018 最大前缀和

PKUSC2018 最大前缀和

时间:2024-11-15 16:01:27浏览次数:1  
标签:前缀 int sum 枚举 msk PKUSC2018 最大

题意

给一个长度为 \(n\) 的整数序列,求其 \(n!\) 种排列方式的最大前缀和(不能为空)的总和。

  • \(n\leq 20\)

解法

设全集为 \(U\),考虑枚举作为最大前缀和的子集 \(S\)。那么要求的就是 \(S\) 排列后严格最大前缀和在最后一个元素取到和方案数和 \(U\backslash S\) 排列后每个前缀和都小于等于 0 的方案数。

后者可以枚举最后一个数填什么转移,前者可以枚举上一个取到严格最大前缀和的子集是哪一个转移,需要注意处理只选一个数的边界情况,复杂度是 \(O(3^n+2^nn)\) 的。

一个精妙的 trick 是考虑 \(S\) 在最后一个位置取到严格最大前缀和相当于把它 reverse 之后前缀和大于 0,这样就可以类比每个前缀和都小于等于 0 做了,同样需要处理只有一个数的情况。

code

代码的边界很不好写。

#include<bits/stdc++.h>

using namespace std;
using E=long long;
const E mod=998244353;

int n;
vector<E> a;

int main(){

  cin>>n;
  a.resize(n);
  for(int i=0; i<n; i++){
    cin>>a[i];
  }

  vector<E> f(1<<n),g(1<<n),sum(1<<n);
  f[0]=g[0]=1;

  for(int msk=1; msk<(1<<n); msk++){
    for(int i=0; i<n; i++) if(msk>>i&1) sum[msk]+=a[i];
    if(sum[msk]<=0) for(int i=0; i<n; i++){
      if((msk>>i&1)==0) continue;
      g[msk]=(g[msk]+g[msk^(1<<i)])%mod;
    }
    if((msk&-msk)==msk) f[msk]=1;
    else for(int i=0; i<n; i++){
      if(msk>>i&1) if(sum[msk^(1<<i)]>0) f[msk]=(f[msk]+f[msk^(1<<i)])%mod;
    }
  }

  E ans=0;
  for(int msk=1; msk<(1<<n); msk++){
    sum[msk]%=mod;
    ans=(ans+f[msk]*g[((1<<n)-1)^msk]%mod*sum[msk])%mod;
    //cerr<<msk<<' '<<f[msk]<<' '<<ans<<endl;
  }

  cout<<(ans%mod+mod)%mod;

  return 0;
}

标签:前缀,int,sum,枚举,msk,PKUSC2018,最大
From: https://www.cnblogs.com/FreshOrange/p/18548118

相关文章

  • MariaDB select多条结果,只取id最大的那一条
    要在MariaDB中选择多条结果但只取 id 最大的一条,可以使用子查询结合 ORDERBY 和 LIMIT。以下是一个示例SQL语句:SQL SELECT*FROMyour_tableORDERBYidDESCLIMIT1;这条语句的作用是从 your_table 表中按 id 降序排序,并只返回第一条记录,即 id 最......
  • 最大岛屿面积
    DFS解法classSolution:dir=[(-1,0),(1,0),(0,-1),(0,1)]defdfs(self,grid,x,y):ifx<0orx>=len(grid)ory<0ory>=len(grid[0])orgrid[x][y]!=1:return0grid[x][y]=0ans=1fo......
  • 深入浅出学算法044-最大整数
    题目描述设有n个正整数(n≤20),将它们联接成一排,组成一个最大的多位整数。      例如:n=3时,3个整数13,312,343联接成的最大整数为:34331213      又如:n=4时,4个整数7,13,4,246联接成的最大整数为:7424613输入输入分2行第一行是n第2行是n个整数输出连接成的多位数......
  • 最大子树和
    题目链接:最大子树和题目描述:小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题。一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题。于是当日课后,小明就向老师提出了这个问题:一株奇怪的花卉,上面共连有\(......
  • 【Azure App Service】在App Service for Windows上验证能占用的内存最大值Y5
    问题描述在创建AppService服务的时候,根据定价层不同,内存使用的最大值也有不同。但在实际测试中,发现内存最大只能占用2GB左右,而定价层中内存分配明明是大于2GB(比如B3定价层的内存为7GB),这是一种什么情况呢?在AppService中Kudu工具上,查看进程分配的内存大小:问题解答使用......
  • 【Azure App Service】在App Service for Windows上验证能占用的内存最大值
    问题描述在创建AppService服务的时候,根据定价层不同,内存使用的最大值也有不同。但在实际测试中,发现内存最大只能占用2GB左右,而定价层中内存分配明明是大于2GB(比如B3定价层的内存为7GB),这是一种什么情况呢?在AppService中Kudu工具上,查看进程分配的内存大小: 问题解答使......
  • 101 最大公约数
    //101最大公约数.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。///*http://oj.daimayuan.top/course/21/problem/486输入T,一共T组数据,每组两个数a,b,输出它们的最大公约数和最小公倍数。输入格式第一行一个数字T。接下来T行,每行两个数字a,b。输出格......
  • C小题目:输入10个整数,将其中最小的数与第1个数对换,将最大的数与最后一个对换。要求写3
    题目要求如下:输入10个整数,将其中最小的数与第1个数对换,将最大的数与最后一个对换。要求写3个函数:(1)输入10个数;(2)进行处理;(3)输出10个数。提示:(1)定义voidinput(int*p)函数,用来输入10个整数,存放到指针变量p所指向的数组中;(2)定义voidmax_min_value(int*p)函数,在指针变量p所指......
  • 【菜笔cf刷题日常-1600】C. Good Subarrays(思维,前缀和)
    链接:Problem-1398C-Codeforces思路:考虑每一个新加入的数对于原有序列(长度、数的总和)需求的变化:如1的加入对于原有序列需求无变化;2 的加入需要原有序列长度增加1;0 的加入需要原有序列数的总和增加1;……因此,将每个数减1(如1变为0,0变为 -1)来代表这个数的......
  • 华为OD机试真题-寻找最大价值的矿堆-2024年OD统一考试(E卷)
    最新华为OD机试考点合集:华为OD机试2024年真题题库(E卷+D卷+C卷)_华为od机试题库-CSDN博客     每一题都含有详细的解题思路和代码注释,精编c++、JAVA、Python三种语言解法。帮助每一位考生轻松、高效刷题。订阅后永久可看,发现新题及时跟新。题目描述给你一个由''(空地)......