1.F-Ginger的数_牛客小白月赛63 (nowcoder.com) (exgcd)
(1)题目大意
(2)解题思路
考虑到只能用[1,m-1]中间的数,因此我们预处理出[1,m-1]中1位的有多少个数字,2位的有多少个数字,一直到m的最高位,然后我们用双重循环枚举需要用到第i位的数字到第j位的数字,中间的全部选上,若中间全部选上的个数已经大于n,则无解,最后第i位和第j位需要的数量位i*x + j * y = gcd(i,j),若剩下的数量不能整除gcd(i,j)说明此方程无解,最后我们考虑把y调的更大,则答案越小,因此我们调节y,若y+1个,则数量等于y*j + i/gcd(i,j),则x - 1个,则数量等于x*i-j/gcd(i,j),最后把x调整到[0,cnt[i]]内就可以,然后ans=min(ans,num_cnt(中间选的)+ x + y)
(3)代码实现
// Problem: Ginger的数
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/49030/F
// Memory Limit: 524288 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include "bits/stdc++.h"
#define rep(i, z, n) for (int i = z; i <= n; i++)
#define per(i, n, z) for (int i = n; i >= z; i--)
#define ll long long
#define db double
#define PII pair<int, int>
#define fi first
#define se second
#define vi vector<int>
#define yes cout << "YES" << endl;
#define no cout << "NO" << endl;
using namespace std;
const int N = 1e5 + 10;
ll cnt[20];
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (!b)
{
x = 1, y = 0;
return a;
}
ll d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
void solve()
{
vector<int> nums;
ll n, m, t;
cin >> n >> m;
t = m - 1;
while (m)
{
nums.push_back(m % 10);
m /= 10;
}
ll pw = 1;
ll ans = 9e18, x, y;
for (int i = 0; i < nums.size(); i++)
{
if (i < nums.size() - 1)
{
cnt[i + 1] = 9 * pw;
}
else
{
cnt[i + 1] = t - pw + 1;
}
if (n % (i + 1) == 0 && n / (i + 1) <= cnt[i + 1])
{
ans = min(ans, n / (i + 1));
}
pw *= 10;
}
for (int i = 1, len = nums.size(); i <= len; i++)
{
for (int j = i + 1; j <= len; j++)
{
ll num = 0, num_cnt = 0;
for (int k = i + 1; k < j; k++)
{
num += cnt[k] * k;
num_cnt += cnt[k];
}
ll res = n - num;
if (res < 0)
continue;
//第i位和第j位凑出res
ll d = exgcd(i, j, x, y);
if (res % d)
continue;
x *= res / d, y *= res / d;
ll up1 = i / d, up2 = j / d;
//将y的数量调到最大
if (y > cnt[j])
{
ll ct = (y - cnt[j] + up1 - 1) / up1;
y -= ct * up1;
x += ct * up2;
}
else if (y < cnt[j])
{
ll ct = (cnt[j] - y) / up1;
y += ct * up1;
x -= ct * up2;
}
if (x < 0)
{
ll ct = (-x + up2 - 1) / up2;
y -= ct * up1;
x += ct * up2;
}
if (x >= 0 && x <= cnt[i] && y >= 0 && y <= cnt[j])
{
ans = min(ans, x + y + num_cnt);
}
}
}
if (ans == 9e18)
{
cout << "GingerNB" << endl;
}
else
{
cout << ans << endl;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T = 1;
cin >> T;
while (T--)
solve();
return 0;
}
2.I-最大公约数求和_中国石油大学(北京)第三届“骏码杯”程序设计竞赛(同步赛) (nowcoder.com)
(1)题目大意
(2)解题思路
考虑积数函数的性质f(xy) = f(x) * f(y),因为i^k是个完全积性函数,我们只需要考虑gcd(i,k),而且gcd(i,k)是个积性函数,若gcd(p,i)不互质,那么我们暴力跑一次,否则就可以进行递推。
(3)代码实现
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <deque>
#include <bitset>
#define rep(i,z,n) for(int i = z;i <= n; i++)
#define per(i,n,z) for(int i = n;i >= z; i--)
#define PII pair<int,int>
#define fi first
#define se second
#define vi vector<int>
#define vl vector<ll>
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) (x).begin(),(x).end()
using namespace std;
using ll = long long;
const int N = 2e7 + 10;
bitset <N> st;
int primes[N],cnt;
int f[N],g[N];
const ll mod = 1e9 + 7;
ll ksm(ll a,ll b)
{
ll res = 1;
while(b) {
if(b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void solve()
{
int n;
ll k;
cin >> n >> k;
ll ans = 1;
g[1] = 1;
rep(i,2,n) {
if(!st[i]) {
primes[++ cnt] = i;
f[i] = ksm(i,k);
g[i] = __gcd(1ll * i,k);
}
for(int j = 1;primes[j] <= n / i;j ++) {
int x = primes[j] * i;
f[x] = 1ll * f[i] * f[primes[j]] % mod;
st.flip(x);
if(i % primes[j] == 0) {
g[x] = __gcd(x * 1ll,k);
break;
}
g[x] = 1ll * g[i] * g[primes[j]] % mod;
}
ans = (ans + 1ll * f[i] * g[i]) % mod;
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T = 1;
// cin >> T;
while(T --) solve();
return 0;
}
(1)题目大意
(2)解题思路
主要考虑怎么解决根号这个事情,注意到题目的一个条件(a-1)^2<b<a^2。我们假设我们求得是Cn,设An为整数项,Bn为小数项,根据共轭式,An + Bn一定是个整数,则Cn=An+Bn, ,
。
令,
,则
继而推出
化简一下得
再次化简得
移向得
考虑构造系数矩阵
然后矩阵快速幂写写就行了。
(3)代码实现
#include "bits/stdc++.h"
#define ll long long
using namespace std;
struct Mat {
ll dp[2][2],p;
friend Mat operator *(Mat A,Mat B){
Mat res;
for(int i = 0;i < 2;i ++) {
for(int j = 0;j < 2;j ++) {
res.dp[i][j] = 0;
}
}
res.p = A.p;
for(int i = 0;i < 2;i ++) {
for(int j = 0;j < 2;j ++) {
for(int k = 0;k < 2;k ++) {
res.dp[i][j] += A.dp[i][k] * B.dp[k][j];
res.dp[i][j] %= res.p;
}
}
}
return res;
}
};
Mat pow(Mat A,int b,int m)
{
Mat res;
res.dp[0][0] = 1;res.dp[0][1] = 0;
res.dp[1][0] = 0;res.dp[1][1] = 1;
res.p = m,A .p = m;
while(b) {
if(b & 1) res = res * A;
A = A * A;
b >>= 1;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int a,b,n,m;
while(cin >> a >> b >> n >> m) {
if(n == 0) {
cout << 2 % m << endl;
continue;
}
if(n == 1) {
cout << 2 * a % m << endl;
continue;
}
Mat A;
A.dp[0][0] = 2 * a % m;A.dp[0][1] = ((-(a * a - b)) % m + m) % m;
A.dp[1][0] = 1;A.dp[1][1] = 0;A.p = m;
A = pow(A,n - 1,m);
ll ans = A.dp[0][0] * (2 * a % m) % m + A.dp[0][1] * 2 % m;
ans %= m;
cout << ans << '\n';
}
return 0;
}