9.21
(1)sequence ——&和 | 的性质
想到了
越或肯定越大,越与一定不会变大,反而有可能变小;
要求>=k个,所以或就是把所有的都或起来,与则是只与k个(没想到)
想到了按位统计,但没想怎么快速的删除一个与——其实很简单 ,就[0,32]遍历一遍就行然后对应的减掉
#include <queue>
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <utility>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1000005;
const int M=33;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
inline void Max(int &x,int y){if(x<y)x=y;}
inline void Min(int &x,int y){if(x>y)x=y;}
int n,k,a[N],ans1,ans2=0;
int ct[N],b[N];
int main() {
// freopen("sequence.in","r",stdin);
// freopen("my.out","w",stdout);
b[0]=1;
for(int i=1;i<M;i++) b[i]=b[i-1]*2;
n=read();k=read();
for(int i=1;i<=n;i++) a[i]=read(),ans1|=a[i];
for(int i=1;i<=k;i++)
for(int j=0;j<M;j++)
if((a[i]&b[j])==0) ct[j]++;
for(int j=0;j<M;j++)
if(!ct[j]) ans2+=b[j];
for(int i=k+1;i<=n;i++) {
for(int j=0;j<M;j++) {
if((a[i-k]&b[j])==0) ct[j]--;
if((a[i]&b[j])==0) ct[j]++;
}
int mx=0;
for(int j=0;j<M;j++)
if(!ct[j]) mx+=b[j];
ans2=max(mx,ans2);
}
printf("%d %d
",ans1,ans2);
return 0;
}
(2)gift——01 背包变形
我们可以枚举现在没有选择的最小的数字编号是 i,那么这也就 说明 比p[i] 小的都被选择了。那么再枚举一个 j 表示还能选择比 j 小的数(按照原题来说就是还剩 j 块钱),那么 j 必须比 p [ i ] 小,不然的话就可以再选择 p[i]了——这里用背包
设$$ f[i][j]$$表示选择了第 i 到第 n 个数字,和为 j 的方案数。
(f[i][j] = f[i + 1][j] + f[i + 1][j − p[i]])
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1100;
const int P=1e7+7;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
typedef long long LL;
int n,m;
int s[N],p[N];
LL f[N][N],ans;
int main() {
n=read();m=read();
for(int i=1;i<=n;i++) p[i]=read();
sort(p+1,p+1+n);
for(int i=1;i<=n;i++) s[i]=s[i-1]+p[i];
if(s[n]<m) {//Q1
printf("1
");return 0;
}
f[n+1][0]=1;
for(int i=n;i>=1;i--)
for(int j=0;j<=m;j++)
if(j>=p[i]) f[i][j]=(f[i+1][j]+f[i+1][j-p[i]])%P;
else f[i][j]=f[i+1][j];
for(int i=1;i<=n;i++)
for(int j=0;j<p[i];j++)
if(m-s[i-1]-j>=0)
ans=(ans+f[i+1][m-s[i-1]-j])%P;
printf("%lld
",ans);
return 0;
}
Q1 特判 : 如果所有加起来都没那么多钱那么只有一种方案——全买