Cod sursa(job #996128)

Utilizator stefan.petreaStefan Petrea stefan.petrea Data 11 septembrie 2013 08:57:23
Problema Cifra Scor 60
Compilator cpp Status done
Runda Arhiva de probleme Marime 4.15 kb
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <stdlib.h>
#include <string.h>
using namespace std;

/* Note: for some reason, the pp table is computed wrong in index 12 and onwards */

/*
 * To check the solutions here's the correct period table
 * 
 * perl -e 'for(1..100){ $s=0; for($j=1;$j<=$_;$j++){ $s += ($j**$j)%10; $s %= 10; }; print "$s,"; }; print "\n"'
 *
 */

#define min(x,y) (((x)<(y))?(x):(y))
/*
 *
 * http://www.infoarena.ro/problema/cifra
 *
 */

/*
 * phi(10) = phi(2)*phi(5) = 4
 * so
 * a^4 = 1 mod 10  if  (a,n) = 1
 *
 *
 * ^^ this won't help us, so we'll drop math for the moment
 */
class sol {
    ifstream I;
    ofstream O;
    vector<string> v;
    vector<vector<int> > p; // period of i^k with i in [0,10]
    vector<int> pp; //  period of last digit of the sum
    int T;
    public:
         sol() : I("cifra.in") , O("cifra.out") {};
        ~sol() { I.close(); O.close(); };
        void read() {
            I >> T;
            for(int i=0;i<T;i++) {
                string s;
                I >> s;
                v.push_back(s);
            };
        };

        void precompute_p() {
            int i,j;
            int mod = 10;
            for(i=0;i<10;i++) {
                int q=i;
                p.push_back(vector<int>());
                p[i].push_back(i);
                while( (q*i % mod) != p[i][0]) {
                    q = (q*i) % mod;
                    p[i].push_back(q);
                };

                // place last item as first so that
                // the index makes sense as a residue mod period
                int last = p[i].back();
                for(j=p[i].size()-1;j>=1;j--)
                    p[i][j] = p[i][j-1];
                p[i][0] = last;
                //cout<<endl;
            };
        };
        void precompute_pp() {
            int s = 1;
            int i = 2;
            pp.push_back(1);

            /* I checked this period with OEIS, and it agrees with the first few numbers of the digit, check for yourself
             * http://oeis.org/search?q=1%2C5%2C2%2C8%2C3%2C9%2C2%2C8%2C7%2C7%2C8
             *
             * Also, the period comes out right as well. It's 100
             */
            int count[10];
            memset(&count,'\x0',10*sizeof(int));
            count[s]++;
            while(1) {
                int ir = i % 10;
                int k = p[ir][i % p[ir].size()];
                s = (s+k) % 10;
                count[s]++;
                i++;
                pp.push_back(s);

                // make sure that all counts are equal
                // this means we've reached the end of the period
                // (of course this is not entirely correct, would have to do order checking also
                // but it's better than hardcoding it, and oeis agrees it's 100 so whatever, it's correct )
                int period_reached = 1;
                for(int j=1;j<10;j++) {
                    period_reached &= (count[j] == count[0]);
                };
                if(period_reached)
                    break;
            };
            // same thing as above so that index makes sense
            int last = pp.back();
            for(int j=pp.size()-1;j>=1;j--)
                pp[j] = pp[j-1];
            pp[0] = last;
        };
        void print_periods() {
            for(int i=0;i<10;i++) {
                for(int j=0;j<p[i].size();j++) {
                    cout<<p[i][j] << ",";
                };
                cout<<endl;
            };
            cout<<"pp="<<endl;
            for(int i=0;i<pp.size();i++) {
                cout<<pp[i]<<",";
            };
            cout<<endl;
        };
        void solve() {
            precompute_p();
            precompute_pp();
            print_periods();
            cout<<"ppsize="<<pp.size()<<endl;
            for(int i=0;i<v.size();i++) {
                int u = 0;
                int l2 = atoi(v[i].c_str()+v[i].size() - min(3,v[i].size()) );
                //cout <<"l2="<<l2<<endl;
                //cout<<"zz="<<pp[l2 % pp.size()]<<endl;
                O << pp[l2 % pp.size()]<<endl;
            };
        };
};
int main() {
    sol S;
    S.read();
    S.solve();
    //S.write();
}