【zzulioj 2133 密室逃脱】

2133: 密室逃脱
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 163 Solved: 19

SubmitStatusWeb Board
Description
XOR在玩密室逃脱,在某一关中,桌上有一个一张纸,上面写着“请根据所给例子求解答案从而获得密码”,下面写了几个字符串“01 10 11”,而答案为“6”,聪明的XOR立马就知道了这是给出一些二进制数字S,求存在多少对有序二元组(i,j)使得S[i]^S[j] < S[i],现在还有T组数据,每组是n个长度为m的二进制数字,聪明的XOR立马开始动手求解答案。

Input
第一行一个整数T,表示数据组数。
对于每组数据,首先读入两个整数n,m(n*m <= 1000000),接下来为n行,每行为一个长度为m的01串,表示一个二进制数字

Output
对于每个数据,输出一个整数x,表示二元组数目

Sample Input
1
3 2
01
10
11
Sample Output
6

自用考虑每个数最高位的 1 的位置,该位置最高位 1 相同的个数 a,贡献为 a * a,然后加上该位置为1但最高位 1 不是该位置的个数 b,a * (b - a)(因为当x和最高位比自己大的数异或时,x只能放后面),减去相同时的重复算的贡献~整理下 a * b~

AC代码:

#include
#include
#include
using namespace std;
const int K = 1e6 + 10;
typedef long long LL;
char s[K];
LL dp[K],a[K],num[K];
int main()
{
    int T,n,m;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&m);
        memset(dp,0,sizeof(dp));
        memset(a,0,sizeof(a));
        memset(num,0,sizeof(num));
        for(int i = 1; i <= n; i++){
            scanf("%s",s);
            for(int j = m - 1,t = 1; j >= 0; j--,t++)
                if(s[j] == '1')
                    dp[t]++,a[i] = t;
        }
        for(int i = 1; i <= n; i++)
            num[a[i]]++;
        LL ans = 0;
        for(int i = 1; i <= m; i++)
                ans += (LL)(num[i] * dp[i]);
        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(zzulioj)