德玛西亚万岁

简介: 【7月更文挑战第2天】

德玛西亚万岁


题意:n*m的矩阵 1能站人,0不能站人,相邻的地方不能站人,问总方案数?


题解:知识点状态DP.
通过题意我们可以知道:
1,当位置(i,j)为0时,不能站人。
2,如果(i,j)站人,那么[i-1,j],[i+1,j],[i,j+1],[i,j-1]这四个地方不能站;
因为数据量不是很大所以我们可以想到用二进制来表示当前该位置上是否站人。
针对1,我们可以样做,因为那这个位置不能站人,所以他这个为对应的二进制位为0,这样之后判断就可以知道,这个位置可不可以站人了。
针对2,我们先看左右的,由于我们把能不能站人转化成了二进制,那么我们也可以用二进制来表示那些位置上站没站人,然后利用错位来判断是否有相邻的,例如
1010101//原本的二进制 101010//错位之后的二进制 0000000//比较之后
比较之后如果是零就说明他没有相邻的。而如果有相邻的就是这种情况
11011000//原 01101100//错 01001000//结果
我们可以知道前一对11和后一对11他们是相邻的 所以返回值不是0;

然后我们看上下:其实就是在枚举一遍上一层的二进制站位,原理跟左右一样,就是这一层是上一层继承过来的,所以若果没有相邻的也要加上上层的那个状态,
最后不要忘了,一个都不放 也是一种方案;

代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=100000000;
const int MOD=10007;

inline int read() {
   
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[20][1<<16];
string str,s;

#define read read()
int main(){
       
     while(~scanf("%lld%lld",&n,&m)){
   
        p=(1<<m);//总的二进制方案数
        //每次初始化
        for(int i=1;i<=n;i++) dis[i]=0;
        for(int i=0;i<=n;i++)
            for(int j=0;j<p;j++) 
                dp[i][j]=0;

        dp[0][0]=1;//什么都不放也算一种方案数
        for(int i=1;i<=n;i++)
            for(int j=0;j<m;j++){
   
                cin>>l;
                dis[i]=dis[i]|(l<<j);//判断这一个位置有没有 用二进制表示
            }


        for(int i=1;i<=n;i++){
               
            for(int j=0;j<p;j++){
   //用二进制表示当前的状态
                //没有这种状态
                if((j&dis[i])!=j)continue;

                //左右相邻了
                if(j&(j>>1))continue;

                for(int k=0;k<p;k++){
   
                    if(k&j) continue;//上下相邻了 
                    else dp[i][j]=(dp[i][j]+dp[i-1][k])%mod;//可以从上层转移过来
                }
            }
        }
        ans=0;
        for(int i=0;i<p;i++){
   
            ans=(ans+dp[n][i])%mod;
        }
        cout<<ans<<endl;



    }
    return 0;
}

扑克牌


题意:给你n种牌,并给你这n种牌的张数,再给你m张万能牌,让你求最多配出多少套牌(就是n中 种牌,一种一张)

题解:知识点:二分
从整体上来看,配出的多少套牌是单调的,想到二分。
重点说一下check判断函数吧,因为你二分出来结果是,一定要判断结果是否符合,如果你配x套,需要大于m张万能牌,那么这样肯定是不行的,再者一套牌中有两张万能牌也是不符合题意的,所以生成了这两个判断条件。

注意一下:他的右端不要设5e8,我当时就看到他给的范围是5e8我就设的5e8,这样想一下,如果n种牌都有5e8,再有5e8个万能牌,会怎样?当然结果就不在5e8范围内了。所以最右端应该是2*5e8。因为一套牌最多有一个万能牌,所以配出来的,最多加上n种牌数量最多的那个个数。也就是5e8+5e8喽。

代码:

#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=2e5+1010;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;

inline int read() {
   
    int x=0;
    bool t=false;
    char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}

/*priority_queue<ll , vector<ll> , greater<ll> > mn;//上  小根堆         小到大 
priority_queue<ll , vector<ll> , less<ll> > mx;//下       大根堆      大到小
map<ll,ll>mp;*/

ll n,m,t,l,r,p;
ll sum,ans,res,cnt,flag,maxx,minn;
bool isprime[maxn];
ll a[maxn],b[maxn],c[maxn];
ll dis[maxn],vis[maxn];
ll dp[1010][1010];
string str,s;

bool check(ll x){
   
    ll sum=0;
    for(int i=1;i<=n;i++)
        if(a[i]<x) sum+=x-a[i];
    if(sum>min(x,m)) return 0;
    else return 1;
}
#define read read()
int main(){
   
     cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i];
    l=0,r=1e9+10;
    while(l<=r){
   
        ll mid=(l+r)/2;
        if(check(mid)){
   
            ans=mid;
            l=mid+1;
        }else r=mid-1;
    }
    cout<<ans<<endl;
    return 0;
}
目录
相关文章
|
6月前
|
开发者
4月更文挑战赛火热启动,寻找热爱技术内容创作的你
开发者社区4月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
4054 30
|
4月前
|
运维 开发者
|
5月前
|
Shell Linux 开发工具
解决windows系统下运行.sh文件
【6月更文挑战第15天】
246 4
|
30天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
1124 31
|
6月前
|
消息中间件 Kafka 数据库
【后端面经】【消息队列】22 | 消息队列:消息队列可以用来解决什么问题?-02 超时场景+性能问题
【5月更文挑战第7天】 本文介绍了电商中订单超时取消的处理方法,通过使用消息队列实现延时消息。当订单30分钟后未支付,消息队列将触发取消操作,但需注意并发问题,如采用分布式锁或乐观锁避免并发更新订单状态。乐观锁确保只有订单状态为未支付时才允许支付。主流消息队列如RocketMQ支持延迟消息,而Kafka不支持。 使用消息队列的好处在于解耦和提高系统性能、扩展性和可用性。同步调用会导致性能下降,因为必须等待所有调用完成。并发调用虽可提升性能,但仍逊于消息队列,且无法解决扩展性和可用性问题。
112 1
|
6月前
|
人工智能 开发者
7月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区7月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
2660 75
7月更文挑战赛火热启动,坚持热爱坚持创作!
|
16天前
|
druid Java Maven
|
13天前
|
JavaScript
力扣3333.找到初始输入字符串Ⅱ
【10月更文挑战第9天】力扣3333.找到初始输入字符串Ⅱ
29 1
|
6月前
|
Rust Java 开发者
5月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区5月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
2163 150
|
4月前
|
人工智能 开发者
8月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区8月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
2418 18