1. 程式人生 > >【bzoj2749】[HAOI2012]外星人

【bzoj2749】[HAOI2012]外星人

題目連結

。。。。。模型轉化錯了被自己蠢到哭

就首先這題如果說質因數只有 2 的時候,操作次數肯定是 2 的個數
如果質因數不只有

2 的時候
考慮 φ ( i ) 的式子,做一次操作就相當於把每種質因數取一個出來,都減去
1
,然後再質因數分解回去

由於質數除了 2 都是奇數,所以減 1 再質因數分解肯定會多很多

2 出來
形式化點,如果存在除了 2 以外的質因數,我們做一次操作 多出的 2 的個數 1
而我們每次最多隻能刪掉 1 2 ,稍加分析就可以得出
答案就是 能分出的 2 的個數 + N 是否為奇數
因為奇數的時候只有第一次操作沒有 2 可以消,其餘操作每次都有

而“能分出的 2 的個數這個東西”是能線性篩出來的

然後這樣就做完了

程式碼:

#include<cstdio>
#include<vector>
#include<queue>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<stack>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long LL;

const int INF = 2147483647;
const int maxn = 100010;

LL ans,f[maxn],pri[maxn],tot;
bool mark[maxn];

inline LL getint()
{
    LL ret = 0,f = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') ret = ret * 10 + c - '0',c = getchar();
    return ret * f;
}

int main()
{
    #ifdef AMC
        freopen("AMC1.txt","r",stdin);
    #endif
    f[2] = 1;
    for (int i = 2; i <= 100000; i++)
    {
        if (!mark[i])
            pri[++tot] = i , f[i] = i == 2 ? 1 : f[i - 1];
        for (int j = 1; j <= tot; j++)
        {
            if (i * pri[j] > 100000) break;
            mark[i * pri[j]] = 1;
            f[i * pri[j]] = f[i] + f[pri[j]];
            if (i % pri[j] == 0) break;
        }
    }

    int t = getint();
    while (t--)
    {
        ans = 0;
        int n = getint(),flag = 0;
        for (int i = 1; i <= n; i++)
        {
            LL p = getint(),q = getint();
            ans += f[p] * q;
            flag += !(p & 1);
        }
        if (!flag) ans++;
        printf("%lld\n",ans);
    }
    return 0;
}