需要笔试辅导的可以私我,ACM金牌退役选手,已拿腾讯和阿里offer,可以视频会议1V1辅导。
题意:正方形划分为8个部分。
思路:直接判断就行。代码写得臭就不发了。
题意:给定01矩阵,有一些连通的1,用0分割,现在你最多可以把其中1个1替换位置,问替换之后的最大连通块是多大。
思路:为了保证做法不会出错,我们得考虑:
对于2,3众情况,我们把他统一为,如果多个连通块中间只被一个空格隔开,那么答案就是这几个连通块大小之和。同时如果这几个连通块之外还有连通块,那么答案+1。+1是表示用外部的连通块来“填”这个1.
综上,我的代码用并查集实现,这样可以得到每个连通块的编号、大小; 移动1,等效于枚举被填的那个位置,然后看4周会不会贡献,贡献并不是独立的,所以还得用并查集判重;最后判定是否+1;
----代码写得比较长,不要嫌弃----
#include
using namespace std;
const int maxn=410;
int mp[maxn][maxn],fa[maxn*maxn];
int id[maxn][maxn],ans,num[maxn*maxn],cnt;
int tfa[maxn];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int find(int x)
{
if(x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void Merge(int x1,int y1,int x2,int y2)
{
if(mp[x1][y1]&&mp[x2][y2]){
int w=find(id[x1][y1]);
int v=find(id[x2][y2]);
if(w!=v) {
num[v]+=num[w];
ans=max(ans,num[v]);
fa[w]=fa[v];
cnt--;
}
}
}
void add(int i,int j,int &tmp,int &sum)
{
int d=find(id[i][j]),F=1;
for(int i=1;i<=tmp;i++){
if(tfa[i]==d){
F=0; break;
}
}
if(!F) return ;
tmp++;
sum+=num[d];
tfa[tmp]=d;
}
int main()
{
int N,M;
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
scanf("%d",&mp[i][j]);
id[i][j]=(i-1)*M+j;
if(mp[i][j]) {
num[id[i][j]]=1;
ans=1;
cnt++;
}
fa[id[i][j]]=id[i][j];
}
}
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
if(i>1) Merge(i-1,j,i,j);
if(j>1) Merge(i,j-1,i,j);
}
}
if(cnt>2){
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
if(mp[i][j]) continue;
int tmp=0,sum=0;
for(int k=0;k<4;k++){
int nowx=i+dx[k],nowy=j+dy[k];
if(nowx>=1&&nowx<=N&&nowy>=1&&nowy<=M){
if(mp[nowx][nowy]){
add(nowx,nowy,tmp,sum);
}
}
}
if(tmp==cnt) ans=max(ans,sum);
else ans=max(ans,sum+1);
}
}
}
printf("%d\n",ans);
return 0;
}
题意:普通的01背包,但是现在体积可能为负数。
思路:一眼题,因为体积为负数,表示我们的体积会变,这种情况,我们把把变为相反数即可,表示我一开始就装进去,那么在跑背包的时候选择了它的相反数这个物体,表示把他移除。而这个时候所有的物体都是正他体积,跑01背包就行。
注:如果你不会01背包的话,那么你在学习的时候得注意,第二个for倒序遍历,这样防止重复更新答案。或者用二维的dp。
#include
using namespace std;
const int maxn=410;
int c[maxn],v[maxn],ans;
int dp[40010];
int main()
{
int N,M;
scanf("%d%d",&N,&M);
for(int i=1;i<=N;i++){
scanf("%d%d",&c[i],&v[i]);
if(c[i]<=0){ //负的物体取反
ans+=v[i];
M-=c[i];
c[i]=-c[i];
v[i]=-v[i];
}
}
for(int i=1;i<=N;i++) //01背包
for(int j=M;j>=c[i];j--)
dp[j]=max(dp[j],dp[j-c[i]]+v[i]);
for(int i=0;i<=M;i++) {
dp[M]=max(dp[M],dp[i]);
}
printf("%d\n",ans+dp[M]);
return 0;
}
位运算和gcd
容斥原理,求所有m的集合,在这个集合的所有数,求一下lcm(最小公倍数),如果|集合|是奇数,ans+=n/lcm,否则ans-=n/lcm 。
具体的:先从简单的问题走起,问1到10里面多少个2的倍数-------> ans=10/2=5;
问1到10里面多少个5的倍数-------> ans=10/5=2;
问1到10里面多少个2或者5的倍数-------> ans=10/5+10/2-10/10=6;
其实也就是容斥的一种特殊情况----抽屉原理。
所以这里用二进制枚举所有情况(对应1到F),二进制对应的1,表示选择、0表示不选择;然后把1对应的位(if(i&(1<#include