9.21

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\n",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\n");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\n",ans);
	return 0;
}


Q1 特判 : 如果所有加起来都没那么多钱那么只有一种方案——全买

posted @ 2020-10-08 16:53  ke_xin  阅读(40)  评论(0编辑  收藏  举报