函数最值(位运算)
函数最值
题目
给定一个n 个数的数组A,函数F(x) = a[i] * x的第i 个二进制位。求F的最大值,x为整数且0<=x<=m.
输入格式
第一行一个整数 n 表示数组大小
第二行 n 个整数表示 Ai,Ai 有正有负
接下来一个数 m 的二进制表示,从前到后分别是低位到高位
输出格式
F(X)的最大值
样例
输入:
4
-1 1 2 0
0010
输出:
2
样例解释:
n = 4
f(0) = 0
f(1) = -1; (1 = 1 = 1*a[1])
f(2) = 1 (2 = 01(倒序) = 0*a[1]+1*a[2])
f(3) = 0
f(4) =2
数据范围:
30% n<=20
100% n<=100000
题解
题目要求将x拆成二进制后,每个位置是1的,加上对应的a数组中的数。
那么对于30%的数据可以直接枚举,100%的数据显然不可以。
然后会发现这样一个性质:如果每个位置都没有约束,也就是可以随便取了,这时可以O(n)的时间算出答案。
之后我们只要创造没有限制的情况就可以了。
比如对于11001000(正过来了,倒着不舒服)
首先只考虑后三位,如果最后一个1是0的话,这三位随便取了,O(n)算出答案,注意这个答案需要加上最后一个1前面的的所有价值,不包括最后一个1
之后找到第二个1,同理让它成为0,算出答案,
这样其实就是分层处理的,
首先的所有1的价值11001000
之后是 11000000~11000111
10000000~10111111
0~1111111
惊奇的发现每个0~11001000的数全都包含了!
代码实现:像上面一样从后往前扫一遍。
注意:一定要开long long,题面居然没写a的范围!!!
开long long与不开的区别是70分!!!
code
1 /* 2 开Long Long与不开long long 的区别是70分!!! 3 */ 4 5 #include<cstdio> 6 #include<algorithm> 7 #include<cstring> 8 9 using namespace std; 10 11 const int MAXN = 200100; 12 13 long long a[MAXN]; 14 long long m[MAXN]; 15 long long sum = 0,mx = 0,ans,n;//mx谁都不选是0 16 char s[MAXN]; 17 18 inline long long read() { 19 long long x = 0,f = 1;char ch = getchar(); 20 for (; ch<'0'||ch>'9'; ch = getchar() ) 21 if (ch=='-') f = -1; 22 for (; ch>='0'&&ch<='9'; ch = getchar()) 23 x = x*10+ch-'0'; 24 return x*f; 25 } 26 void work(int l,int r) { 27 for (int i=l; i<=r; ++i) { 28 if (a[i] > 0) mx += a[i]; 29 } 30 } 31 int main() { 32 33 34 n = read(); 35 for (int i=1; i<=n; ++i) a[i] = read(); 36 scanf("%s",s); 37 int len = strlen(s); 38 for (int i=0; i<len; ++i) { 39 if (s[i]=='1') { 40 m[i+1] = 1;sum += a[i+1]; 41 } 42 else m[i+1] = 0; 43 } 44 ans = sum; 45 long long tmp;int L = 1; 46 for (int i=1; i<=n; ++i) { 47 if (m[i]==1) { 48 sum -= a[i]; 49 work(L,i-1);L = i; 50 tmp = max(mx+sum,mx); 51 ans = max(tmp,ans); 52 } 53 } 54 printf("%lld",ans); 55 return 0; 56 }
清北刷题班 by ccl 函数最值