因为以前也没怎么碰到过NADN的题目,所以第一次碰非常陌生没有感觉。什么等价类什么东西完全懵逼。下面我尽量朴素的讲解一下我的看法。
首先NAND 可以模拟任何一种位运算。(xor,and ,not,or)这个记一下就好,好像或非也是这样。 然后显然可以知道如果a1~an z在二进制下P和Q位都相等,那么显然怎么搞这两位在ai上都还是相等的。(这个很显然)然后我们就称这些位上构成一个等价类,然后网上大都就直接说等价类是互相独立的。这话听着很正确,但是似乎也不是那么容易理解和证明,然后我就想了个比较傻逼的方法,
对于每一位,我们枚举每一个数,若该数该位上为0,我们就对这个数取非
然后把所有数取与
该位上都是1,所以取与后一定是1;对于其他位,只要有这两位不同的数存在,那么这位一定是0
最后取与的结果中与该位全部相同的位都是1,其余都是0,、
这样好像就把各个等价类成功分离了。然后我们大概就可以说他们是互相独立的了。其实这也就是把他们分离出来的方法也就相当于线性基,然后做一下昨天用的位数dp就好了,这里注意一下,这个 题的线性基是没有任何一位会重复的,所以对于每个线性基能造成的影响不过让这些位变成0或1两种,所以用or或xor运算是一样的
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define eps 1e-8
#define maxn 510
#define Abs(x) ((x) > 0 ? (x) : (-(x)))
#define forup(i,a,b) for(int i=(a);i<=(b);i++)
#define fordown(i,a,b) for(int i=(a);i>=(b);i--)
using namespace std;
struct yts
{
long double b[maxn];
int val;
}a[maxn];
int n,ans,m,num;
int vis[maxn];
bool cmp(yts x,yts y)
{
return x.val<y.val;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
cin>>a[i].b[j];
for (int i=1;i<=n;i++) scanf("%d",&a[i].val);
sort(a+1,a+n+1,cmp);
/*for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (fabs(a[i].b[j])>eps)
{
if (!vis[j])
{
vis[j]=i;
ans+=a[i].val;num++;
break;
}
else
{
long double t=(long double)a[i].b[j]/(long double)a[vis[j]].b[j];
for (int k=j;k<=m;k++)
a[i].b[k]-=t*a[vis[j]].b[k];
}
}*/
forup(i,1,m)
{int b=0;
forup(j,1,n)
{ if(fabs(a[j].b[i])>eps&&!vis[j])
{ b=j;vis[j]=1;
break;
}
}
if(b!=0) {num++;ans=ans+a[b].val;}
else continue;
forup(j,1,n)
{if(j!=b&&fabs(a[j].b[i])>eps)
{ long double tmp=(long double)a[j].b[i]/(long double)a[b].b[i];
forup(k,1,m)
a[j].b[k]=a[j].b[k]-tmp*a[b].b[k];
}
}
}
printf("%d %d\n",num,ans);
return 0;
}