Wannafly挑战赛29 B 白井黑子(暴力枚举)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37025443/article/details/84452794

题目链接

题意:

给你长度为n的序列,然后一个k。f(ai) 是 ai 各数位相乘的结果
如果 f(ai) x f(aj) 不能被某个自然数的 k 次幂表示 的话,那么 kuroko 就能对这两个物品使用能力。

有多少对物品她可以对其施展能力,知道了这个后她就知道自己能完成多少测验了。

这里认为任何自然数的 0 次幂都是 1。

解析:

这道题可以用暴力枚举O(60*40*20*20)也可以用前缀和做。

我用的是bitset<1e5>来记录后缀性质来做的,代码写得有点臭了,所以贴两个大佬得代码学习一下

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5+100;
typedef long long ll;
bitset<MAXN> dp[6][150];
 
ll b[MAXN];
ll a[MAXN][6];
 
 
map<int,int> mp;
 
inline void solve(int res,int x)
{
    if(mp.count(res)) a[x][mp[res]]++;
    else
    {
        switch(res)
        {
            case 4:
                a[x][mp[2]]+=2;
                return;
            case 6:
                a[x][mp[2]]++;
                a[x][mp[3]]++;
                return ;
            case 8:
                a[x][mp[2]]+=3;
                return;
            case 9:
                a[x][mp[3]]+=2;
                return;
        }
    }
}
 
 
int main()
{
    int n;
    ll k;
    mp[2]=0;
    mp[3]=1;
    mp[5]=2;
    mp[7]=3;
    mp[0]=4;
    mp[1]=5;
    scanf("%d%lld",&n,&k);
    for(int i=1;i<=n;i++)
    {
        ll tmp;
        scanf("%lld",&tmp);
        if(!tmp) b[i]=0;
        else b[i]=1;
        while(tmp)
        {
            int res=tmp%10;
            b[i]*=res;
            solve(res,i);
            tmp=tmp/10;
        }
    }
    ll ans=1ll*n*(n-1)/2;
    int ze,one;
    if(k>150)
    {
        ze=one=0;
        for(int i=n;i>=1;i--)
        {
            if(b[i]==0)
            {
                ans-=(n-i);
                ze++;
            }
            else if(b[i]==1)
            {
                ans-=one+ze;
                one++;
            }
            else
            {
                ans-=ze;
            }
        }
        printf("%lld\n",ans);
        return 0;
    }
 
    bitset<MAXN> res;
    //bitset<MAXN> ano;
    bitset<MAXN> past;
 
    ze=0;
    if(k==0)
    {
        one=0;
        for(int i=1;i<=n;i++)
        {
            if(b[i]==1) one++;
        }
        ans-=1ll*one*(one-1)/2;
        printf("%lld\n",ans);
        return 0;
    }
    past.reset();
    for(int i=n;i>=1;i--)
    {
        res=past;
        if(b[i]==0)
        {
            ans-=(n-i);
            ze++;
            past.set(i);
            continue;
        }
        for(int j=0;j<4;j++)
        {
            int tmp=(k-a[i][j]%k)%k;
            res&=dp[j][tmp];
        }
        ans-=res.count()+ze;
        //ano.reset();
        //ano.set(i);
        for(int j=0;j<4;j++)
        {
            int tmp=a[i][j]%k;
            dp[j][tmp].set(i);
        }
        past.set(i);
    }
    printf("%lld\n",ans);
}

大佬1:暴力枚举

#include <bits/stdc++.h>
#define N 100010
 
typedef long long ll;
const int fy[10][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}, {0, 1, 0, 0},
    {2, 0, 0, 0}, {0, 0, 1, 0}, {1, 1, 0, 0}, {0, 0, 0, 1}, {3, 0, 0, 0}, {0, 2, 0, 0}};
 
char s[25];
ll K, ans, tot, te = 0;
int n;
int f[60][40][20][20];
 
int main() {
    int i, j, k, l, z, ni, nj, nk, nl; char *p;
    scanf("%d%lld", &n, &K);
    tot = n * (n - 1ll) / 2;
    for (z = 0; z < n; ++z) {
        scanf("%s", s); i = j = k = l = 0;
        for (p = s; *p; ++p) {
            if (*p == 48) break;
            i += fy[*p & 15][0];
            j += fy[*p & 15][1];
            k += fy[*p & 15][2];
            l += fy[*p & 15][3];
        }
        if (*p == 48) --z, --n;
        else if (K) ++f[i % K][j % K][k % K][l % K];
        else te += !(i||j||k||l);
    }
    if (!K) {
        ans = te * (te - 1ll);
        return printf("%lld\n", tot - ans / 2), 0;
    }
    tot = n * (n - 1ll) / 2;
    if (K > 120) ans = f[0][0][0][0] * (f[0][0][0][0] - 1ll);
    else
        for (i = 0; i < 60 && i < K; ++i)
            for (ni = i ? K - i : 0, j = 0; j < 40 && j < K; ++j)
                for (nj = j ? K - j : 0, k = 0; k < 20 && k < K; ++k)
                    for (nk = k ? K - k : 0, l = 0; l < 20 && l < K; ++l) {
                        nl = l ? K - l : 0;
                        if (i==ni && j==nj && k==nk && l==nl)
                            ans += f[i][j][k][l] * (f[i][j][k][l] - 1ll);
                        else if (ni<60 && nj<40 && nk<20 && nl<20)
                            ans += (ll)f[i][j][k][l] * f[ni][nj][nk][nl];
                    }
    printf("%lld\n", tot - ans / 2);
    return 0;
}

大佬2:map<vector<ll>,int> 维护前缀和,与我的类似,但是写的比较清爽

#include<bits/stdc++.h>
using namespace std;
using LL=long long;
const LL mos[4]={2,3,5,7};
map<vector<LL>,LL>my;
 
int main()
{
    LL n,k;
    scanf("%lld%lld",&n,&k);
    vector<LL>s1;
    vector<LL>s2;
    s1.resize(4),s2.resize(4);
    int i,j;
    LL t;
    LL cnt=0;
    LL ans=0;
    for(i=0;i<n;i++)
    {
        scanf("%lld",&t);
        LL now=1;
        while(t)
        {
            now*=t%10;
            t/=10;
        }
        if(k==0)
        {
            if(now==1)
                cnt++;
            continue;
        }
        if(now==0)
        {
            cnt++;
            continue;
        }
        for(j=0;j<4;j++)
        {
            int num=0;
            while(now%mos[j]==0)
            {
                now/=mos[j];
                num++;
            }
            num%=k;
            s1[j]=num;
            s2[j]=(k-num)%k;
        }
        ans+=my[s2];
        my[s1]++;
    }  
    if(k==0){
        ans=n*(n-1)/2-cnt*(cnt-1)/2;
    }
    else
    {
        ans=ans+cnt*(n-cnt)+(cnt-1)*cnt/2;
        ans=n*(n-1)/2-ans;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/84452794