备战省赛组队训练赛第十六场 Winner Winner

题目描述
The FZU Code Carnival is a programming competetion hosted by the ACM-ICPC Training Center of Fuzhou University. The activity mainly includes the programming contest like ACM-ICPC and strive to provide participants with interesting code challenges in the future.
Before the competition begins, YellowStar wants to know which teams are likely to be winners. YellowStar counted the skills of each team, including data structure, dynamic programming, graph theory, etc. In order to simplify the forecasting model, YellowStar only lists M skills and the skills mastered by each team are represented by a 01 sequence of length M. 1 means that the team has mastered this skill, and 0 does not.
If a team is weaker than other teams, this team cannot be a winner. Otherwise, YellowStar thinks the team may win. Team A(a1, a2, …, aM ) is weaker than team B(b1, b2, …, bM ) if ∀i ∈ [1, M], ai ≤ bi and ∃i ∈ [1, M], ai < bi.
Since YellowStar is busy preparing for the FZU Code Carnival recently, he dosen’t have time to forecast which team will be the winner in the N teams. So he asks you to write a program to calculate the number of teams that might be winners.

输入
Input is given from Standard Input in the following format:
N M
s1 s2 . . . sN
The binary representation of si indicates the skills mastered by teami.
Constraints
1 ≤ N ≤ 2 × 106
1 ≤ M ≤ 20
0 ≤ si < 2M

输出
Print one line denotes the answer.

input
3 3
2 5 6
output
2
题目大意:
emmmmm,这样来说吧,有n个ACM队伍,这些队伍中需要用到m个知识,比如数论、图论、dp……,1代表会该知识点,0代表不会该知识(这里要用二进制来看),问最终会有多少个队伍赢得比赛;
拿题目中给的样例来说,3个队伍,需要具备3个知识,其中第一个队伍会
第二个知识点(010)、第二个队伍(101)会第一个和第三个知识点、第三个队伍(110)会第三个和第二个知识点;
再来看其对应的二进制数

里面每行都是对应列能赢的队伍110101010
100100000
010001
000000

通过这个表格就可以看出会110技能的赢不了会101的技能的,那么答案就是2个队伍了
分析:

我们可以借助状压DP的思想来用位操作实现上面表格的操作;

#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <set>
#include <stack>
using namespace std;
typedef long long ll;
const int N = 2e6+10;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Abs(x) ((x)>=0?(x):-(x))
int ma[(1<<21)];
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int n,m;
    scanf("%d%d",&n,&m);

    ll maxv=-1;
    for(int i=1;i<=n;i++){ll u;
        scanf("%lld",&u);
        ma[u]++;
        maxv=max(maxv,u);//取一个最大值,然后从最大值开始枚举
    }

    int cnt=0;
    for(ll i=maxv;i>=0;i--){
        if(ma[i]!=0){
            for(int j=0;j<m;j++){
                int t=(i^((1<<j)&i));//这一步就是实现了上表的操作,如110能赢010
                if(ma[t]>0&&t!=i)
                    cnt+=ma[t];//cnt统计的是有多少个队伍会输掉比赛
                ma[t]=-1;//在这里打一个标记
            }
            ma[i]=0;
        }
    }
    printf("%d\n",n-cnt);
    return 0;
 }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值