• BZOJ 3198: [Sdoi2013]spring [容斥原理 哈希表]


    3198: [Sdoi2013]spring

    题意:n个物品6个属性,求有多少不同的年份i,j满足有k个属性对应相等


    一开始读错题了,注意是对应相等 第i个属性只能和第i个属性对应

    容斥一下

    [恰好k个相等=ge k个相等 - ge k+1个相等 + ge k+2个相等 ... ]

    (2^6)枚举哪些属性对应相等,哈希一下计算这些属性相等的个数,这时候其他是任意的因为是(ge)
    这样还不行,容斥系数还要乘上(inom{i}{k}),因为两个k+1个属性对应相等的物品贡献了(inom{k+1}{k})个k个属性相等
    其实就是说,比如(ge k)的时候我们求到的(ge k)个相等的方案数,并不是这样的物品对个数,对于一个(k+i)个属性对应相等的物品对我们其实考虑了(inom{k+i}{k})次,这里本身就出现了重复(不是容斥的原因是我们统计个数的原因),所以要额外消去这个的影响,方法就是乘上那个组合数
    我在这里进行了证明


    属性值太大很容易冲突所以要用哈希表
    然后去学了哈希表...貌似P越小越快啊


    ```cpp #include #include #include #include using namespace std; typedef long long ll; const int N=1e5+5, M=23333, P=1001001;//1234567; inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f; }

    int n, k, a[N][7], c[7][7];
    struct HashList{
    struct meow{int id, c, ne;} e[N*64];
    int cnt, h[P], tim[P], Cl;
    inline void ini(){Cl++;}
    inline bool same(int x, int y, int s) {
    for(int i=1; i<=6; i++)
    if(s&(1<<(i-1)) && a[x][i] != a[y][i]) return false;
    return true;
    }
    int hash(int a, int s) {
    ll val=0;
    for(int j=1; j<=6; j++)
    if(s&(1<<(j-1))) val = (val
    M%P + a[j]%P)%P;
    return val;
    }
    int insert(int id, int s) {
    int val=hash(a[id], s); //printf("ins %d %d %d ",id,s,val);
    if(tim[val] != Cl) h[val]=0, tim[val]=Cl;
    for(int i=h[val];i;i=e[i].ne)
    if(same(e[i].id, id, s)) {e[i].c++; return e[i].c-1;}
    e[++cnt]=(meow){id, 1, h[val]}; h[val]=cnt;
    return 0;
    }
    }H;
    ll cal(int s) {
    H.ini();
    ll ans=0;
    for(int i=1; i<=n; i++)
    ans += H.insert(i, s);
    return ans;
    }
    inline int one(int x) {
    int ans=0;
    while(x) ans++, x&=x-1;
    return ans;
    }
    ll cnt[7];
    int main() {
    //freopen("in","r",stdin);
    n=read(); k=read();
    for(int i=1; i<=n; i++)
    for(int j=1; j<=6; j++) a[i][j]=read();
    c[0][0]=1;
    for(int i=1; i<=6; i++) {
    c[i][0]=1;
    for(int j=1; j<=i; j++) c[i][j] = c[i-1][j] + c[i-1][j-1];
    }
    int All=1<<6;
    for(int s=0; s<All; s++) cnt[one(s)] += cal(s);
    ll ans=0;
    for(int i=k; i<=6; i++) ans += (( (i-k)&1 ) ? -1 : 1) * c[i][k] * cnt[i];
    printf("%lld ",ans);
    }

  • 相关阅读:
    hexo命令报错
    开始使用hexo
    javascript 获取元素
    javascript DOM属性操作
    javascript DOM节点操作
    javascript 完美拖动效果
    ubuantu 18.04 LTS 版本解决网易云安装启动问题
    课后作业-阅读任务-阅读提问-3
    C# 并行循环
    C# 委托
  • 原文地址:https://www.cnblogs.com/candy99/p/6616809.html
Copyright © 2020-2023  润新知