题目链接
题意:
给你长度为n的序列,然后一个k。f(ai) 是 ai 各数位相乘的结果
如果 f(ai) x f(aj) 不能被某个自然数的 k 次幂表示 的话,那么 kuroko 就能对这两个物品使用能力。
有多少对物品她可以对其施展能力,知道了这个后她就知道自己能完成多少测验了。
这里认为任何自然数的 0 次幂都是 1。
解析:
这道题可以用暴力枚举O(60*40*20*20)也可以用前缀和做。
我用的是bitset<1e5>来记录后缀性质来做的,代码写得有点臭了,所以贴两个大佬得代码学习一下
#include
using namespace std;
const int MAXN = 1e5+100;
typedef long long ll;
bitset dp[6][150];
ll b[MAXN];
ll a[MAXN][6];
map 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 res;
//bitset ano;
bitset 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
#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
#include
using namespace std;
using LL=long long;
const LL mos[4]={2,3,5,7};
map,LL>my;
int main()
{
LL n,k;
scanf("%lld%lld",&n,&k);
vectors1;
vectors2;
s1.resize(4),s2.resize(4);
int i,j;
LL t;
LL cnt=0;
LL ans=0;
for(i=0;i