Light OJ: 1144 – Ray Gun

0
Problem Link : http://www.lightoj.com/volume_showproblem.php?problem=1144
Solution Idea:

    • There are many observations to make in order to get to a working solution.
    • For every lattice point (i, j), the ray that intersects it is unique and it’s identified by the pair , where g is the gcd of i and j.
    • The problem is now reduced to counting the number of irreducible fractions such that a ≤ N and b ≤ M. This is the same as counting for every i between 1 and N, the amount of numbers in the range [1, M] that are coprime with i.
    • Consider a certain number x with prime factors p1, p2. How do we know how many numbers in range [1, M] are coprime with it? That’s equal to M minus the amount of multiples of p1 minus the amount of multiples of p2 plus the amount of multiples of p1 * p2. This is inclusion-exclusion, and in general, if the amount of elements is even, we add, otherwise, we subtract.
    • So now we have a working (but slow) solution: Iterate over every i in the range [1, N] and for every i, factorize it, try out all combinations of primes and then, for every combination that results in a number k, add if the amount of primes is even or subtract if the amount of primes is odd.
    • The previous approach is very slow for two reasons: You’ll be factorizing each number every time and you’ll be doing a lot of repeated work. Every combination of primes you try out at each step will result in a certain number k. A crucial observation is that the higher exponent of that number k will be 1, because we’re trying combinations of different primes. Another crucial observation is that this number k will be seen times in total. Finally, each time we see it, it will contribute by to the final answer (or if the amount of primes is odd).
    • Knowing all this, we can precalculate a lot of stuff and then solve each test case in O(N). We should precalculate the amount of prime factors of every number in the range [1, 106] (this can be done with a simple sieve), and we should cross out numbers that have some prime with an exponent higher than 1 (in other words, multiples of some square). Once we have precalculated all that, we simply iterate from 1 to N and for every number x that we didn’t cross out, we add (or subtract) to our answer.
    • Final observations: We should add 2 to our answer (the two borders). If N = 0, the answer is 1, except M = 0 too, in which case the answer is 0.

(This solution idea is from this link )


SPOJ: SQFREE – Square-free integers

0

Problem Link : http://www.spoj.com/problems/SQFREE/

Solution Idea:

Basic operation of mobius function. Generate mobius function. Then think about every number whose mobius function value is not zero. If we squre them then something we can get.


#include <bits/stdc++.h>

#define ms(a,b)          memset(a, b, sizeof(a))
#define pb(a)            push_back(a)

#define ss               second
#define sqr(x)           (x)*(x)

#define SZ(a)            (int)a.size()
#define sf(a)            scanf("%d",&a)
#define sfl(a)           scanf("%lld",&a)


#define TEST_CASE(t)     for(int z=1;z<=t;z++)
#define ll long long

using namespace std;

#define mx 10000007

int ara[mx];
vector<ll>num,mobius,prime;
bitset<mx/2>vis;

void sieve()
{
    int x=mx/2,y=sqrt(mx)/2;

    for(int i=1;i<y;i++)
    {
        for(int j=i*(i+1)*2;j<x;j+=(2*i+1))
            vis[j]=1;
    }

    prime.pb(2);
    for(int i=3;i<mx;i+=2)
        if(vis[i/2]==0)
            prime.pb(i);

}

void precal()
{
    fill(ara,ara+mx,1);
    for(int i=0;prime[i]*prime[i]<mx;i++)
    {
        ll x=prime[i]*prime[i];
        for(int j=x;j<mx;j+=x)
            ara[j]=0;
    }

    for(int i=0;i<SZ(prime);i++)
    {
        int x=prime[i];
        for(int j=x;j<mx;j+=x)
            ara[j]*=-1;
    }

    for(int i=2;i<mx;i++)
    {
        if(ara[i]==0) continue;
        num.pb(i);
        mobius.pb(ara[i]);
    }

}

int main()
{

//    freopen("in.txt","r",stdin);
//	  freopen("out.txt","w",stdout);
    sieve();
    precal();

    int t;
    sf(t);
    TEST_CASE(t)
    {
        ll n;
        sfl(n);

        ll ans=n;

        for(int i=0;i<SZ(num);i++)
        {
            ll x=num[i];
            ll zz=sqr(x);
            if(zz>n) break;
            int y=mobius[i];
            ans+=mobius[i]*(n/zz);
        }

        printf("%lld\n",ans);

    }

    return 0;
}