数论杂题

URAL1095

题意:给定 \(t\) 个数字,每个数字不超过 \(20\) 位,并且每个数字的数码里都含有至少一组 \(1,2,3,4\)。对每个数字的数码进行重新排序,使得它能被 \(7\) 整除。

\(1 \le t \le 10000\)

分析:这题的关键在于“每个数字的数码里都含有至少一组 \(1,2,3,4\)”这个条件。这个条件这么奇怪,肯定是题目的突破口!可惜上课的时候没有注意繁杂的文字中这一句微小的条件。

注意到 \(4123 \% 7 = 0,1324 \% 7 = 1......\) 写一写发现这四个数字排列中可以把模 \(7\) 的所有余数取遍。那么我们把这些数字提出来,其他数字随便排,后面四位遍历一遍这七个四位数,如果可以整除就输出。因为放到后四位的时候这个数字相当于 \(XXXX...000y\),其中 \(y\) 就是这个四位数模 \(7\) 的余数(因为减掉若干个 \(7\) 之后与原来同余)。那么这七个数组成 \(7\) 的同余类,一定有一个整除 \(7\)

注意不能有前导 \(0\),所以我们尽量从大到小排序其他的数码。其他数字都是 \(0\) 的时候直接输出 \(4123000...\) 即可。

#include<bits/stdc++.h>
using namespace std;
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef __int128_t lll;
typedef pair<int, int> pii;
const int inf = 1e9;
lll dem[] = {4123,1324,1234,2341,2314,2413,2134};
bool vis[5];
void output(lll x) {
    string s;
    while(x) {
        s += char((x % 10) + '0');
        x /= 10;
    }
    reverse(s.begin(), s.end());
    cout << s << endl;
    return;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    int t; cin >> t;
    while(t--) {
        memset(vis, 0, sizeof(vis));
        string s; cin >> s;
        lll ans = 0;
        lll ch[25]; int cnt = 0;
        f(i, 0, s.size() - 1) {
            if(s[i]-'0'<5 && s[i]-'0'!=0 && !vis[s[i]-'0'])
                vis[s[i]-'0']=1;
            else ch[++cnt]=s[i]-'0';
        }
        sort(ch + 1, ch + cnt + 1, greater<lll>());
        if(ch[1] == 0) {
            cout << "4123";
            f(i, 1, cnt) output(ch[i]);
            cout << endl;
            continue;
        }
        else {
            f(i, 1, cnt) {ans *= 10; ans += ch[i];}
            ans *= 10000;
            f(j,0 , 6) if((ans + dem[j]) % 7 == 0) {
                output(ans + dem[j]); break;
            }
        }
    }
    return 0;
}
ARC149A

居然被一道 A 题 AK 了。。

题意:给定 \(n,m\),求满足以下条件的最大数 \(X\)

  • 位数在 \(n\) 以下。
  • 能被 \(m\) 整除。
  • 每一位的数码都相同。
    \(n \le 10^5, m \le 10^9\)

分析:考虑枚举位数和数码,关键在于判断是否整除。
其实也很好判断,就是可以通过 \(i-1\) 位,数码都是 \(q\) 的数字模 \(m\) 的余数,递推出 \(i\) 位,数码都是 \(q\) 的数字模 \(m\) 的余数,只需要乘 \(10\)\(q\) 即可。(模对于加法和乘法是有传递性的)然后就做完了。。。

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    time_t start = clock();
    //think twice,code once.
    //think once,debug forever.
    int n ,m; cin >> n >> m;
    int now = 0;
    int maxi = 0, maxt = 0;
    f(i, 1, n) {
        now = (now * 10 + 1) % m;
        f(j, 1, 9) {
            if((now * j) % m == 0) {
                maxi = i, maxt = j;
            }
        }
    }
    if(maxi == 0 ) cout << -1 << endl;
    else {
        f(i, 1, maxi) cout << maxt;
    }
    time_t finish = clock();
    //cout << "time used:" << (finish-start) * 1.0 / CLOCKS_PER_SEC <<"s"<< endl;
    return 0;
}
预处理分解质因数

考虑 \(m\) 次询问,每次查询 \(a_i\) 的所有质因数。
\(m \le 10^6, a_i \le 10^7\)

可以做一张表,每个数字不超过十个质因数。
埃筛可以做到 \(O(a_i \ln \ln a_i)\)
但是其实我们只需要存储每个数字的最小质因数即可,这个线性筛可以做到。然后每次只需要跳转即可。

posted @ 2022-10-04 14:11  OIer某罗  阅读(18)  评论(0编辑  收藏  举报