求a ^ 3 + b ^ 3 + c ^ 3 = x 有无解 有则输出
a b c 的绝对值小于5000 x在0到200
我看到x范围比较小就觉得可以打表
问题是怎么写一个比较快的打表程序
一开始想的是c^3用map存,然后对于每一个x枚举a b
但这样太慢了
其实很接近了
应该是a ^ 3 + b ^ 3用map存,然后每次枚举c
这样打表的就很快了
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(ll i = (a); i <= (b); i++)
using namespace std;
int ans[250][3] =
{
0,5000,-5000,
1,5000,-5000,
-486,4375,-4373,
4,4,-5,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-205,644,-637,
44,168,-169,
2,5000,-5000,
-52,217,-216,
-353,683,-650,
-641,843,-695,
7,10,-11,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-262,332,-265,
-588,4118,-4114,
2195,2977,-3331,
-1276,1671,-1373,
47,91,-95,
-741,2833,-2816,
-287,445,-401,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
8,8,-10,
1839,2357,-2683,
237,2106,-2107,
3,5000,-5000,
-249,2269,-2268,
-69,235,-233,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-244,1557,-1555,
-509,1154,-1120,
2358,2731,-3223,
-84,445,-444,
16,25,-27,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-307,837,-823,
-5,8,-7,
1709,2025,-2369,
-473,815,-758,
49,139,-141,
-1247,3991,-3950,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
602,659,-796,
1000000000,1000000000,1000000000,
1518,2141,-2370,
-648,3891,-3885,
1837,3131,-3329,
505,559,-672,
361,982,-998,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-163,1202,-1201,
668,845,-966,
-1561,2903,-2744,
102,146,-161,
4,5000,-5000,
403,903,-929,
1,4,1,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
134,398,-403,
824,2325,-2359,
401,443,-533,
-104,434,-432,
-146,344,-335,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-829,2123,-2080,
-196,711,-706,
-706,1366,-1300,
-1719,2638,-2368,
847,1188,-1317,
1315,3651,-3707,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-1972,4271,-4126,
-1282,1686,-1390,
1953,2036,-2514,
365,1798,-1803,
-2912,3992,-3389,
861,4039,-4052,
-98,253,-248,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
14,20,-22,
-991,3200,-3168,
-1638,2391,-2101,
-622,984,-893,
-903,1870,-1797,
319,2325,-2327,
118,229,-239,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-4,8,-7,
-1165,2760,-2689,
947,1117,-1309,
-948,1345,-1165,
853,2924,-2948,
1000000000,1000000000,1000000000,
-2312,4966,-4793,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
8,11,-12,
-757,1945,-1906,
-555,962,-896,
383,4327,-4328,
-1673,3789,-3677,
1219,2725,-2804,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-16,38,-37,
0,5,-1,
5,5000,-5000,
-419,2217,-2212,
-3881,4988,-4034,
-726,3997,-3989,
-1238,1801,-1580,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
2,5,-1,
167,389,-399,
-1766,3203,-3013,
-629,1395,-1351,
816,946,-1116,
-428,801,-758,
-77,103,-86,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
104,116,-139,
-3,8,-7,
1000000000,1000000000,1000000000,
-2552,3342,-2746,
-7,10,-8,
-263,376,-327,
1528,2131,-2366,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
260,317,-367,
215,447,-463,
486,741,-805,
-695,3744,-3736,
-516,2145,-2135,
-1049,3721,-3693,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
383,1526,-1534,
-1654,3972,-3874,
-2476,4980,-4767,
-1417,4180,-4125,
-2943,4033,-3423,
-59,79,-66,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-574,890,-802,
-1012,1521,-1354,
-2149,4047,-3834,
891,1178,-1328,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-170,349,-335,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-160,1169,-1168,
-10,15,-13,
1503,2691,-2839,
1000000000,1000000000,1000000000,
974,4861,-4874,
-29,91,-90,
976,4876,-4889,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
5,5,-4,
-1092,2000,-1885,
318,1635,-1639,
-1403,1974,-1702,
-593,4815,-4812,
-215,399,-377,
16,16,-20,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
1000000000,1000000000,1000000000,
-579,1112,-1057,
-1606,3026,-2867,
-1347,3809,-3752,
508,2199,-2208,
-638,2334,-2318,
};
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int x; scanf("%d", &x);
if(ans[x][0] == 1e9) puts("impossible");
else printf("%d %d %d\n", ans[x][0], ans[x][1], ans[x][2]);
}
return 0;
}
很容易想到质数的分布是比较稀疏的
所以大范围是肯定小于1 / 3的
小范围暴力
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int check(int x)
{
if(x == 1) return true;
for(int i = 2; i * i <= x; i++)
if(x % i == 0)
return false;
return true;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int l, r;
scanf("%d%d", &l, &r);
if(r - l > 1e3) puts("Yes");
else
{
int cnt = 0;
_for(i, l, r)
cnt += check(i);
if(3 * cnt < (r - l + 1)) puts("Yes");
else puts("No");
}
}
return 0;
}
套了kuangbin的模板
但一直WA
其实思路完全正确,就是小细节没弄好
一个是计算因数出现了多少次的时候确实会爆long long 因为是阶乘的因子数不是一个数的因子数
一个是有个地方会爆long long 我意识到了但没处理好
应该反过来写,用除法 就可以避免这个问题
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int S = 8;
ll x, y, a[N];
int m;
ll factor[100];
int tol;
ll gcd(ll a, ll b)
{
ll t;
while(b)
{
t = a;
a = b;
b = t % b;
}
if(a >= 0) return a;
return -a;
}
ll binpow(ll a, ll b, ll c)
{
a %= c;
b %= c;
ll ret = 0, tmp = a;
while(b)
{
if(b & 1)
{
ret += tmp;
if(ret > c) ret -= c;
}
tmp <<= 1;
if(tmp > c) tmp -= c;
b >>= 1;
}
return ret;
}
ll pow_mod(ll a, ll n, ll mod)
{
ll ret = 1;
ll temp = a % mod;
while(n)
{
if(n & 1) ret = binpow(ret, temp, mod);
temp = binpow(temp, temp, mod);
n >>= 1;
}
return ret;
}
bool check(ll a, ll n, ll x, ll t)
{
ll ret = pow_mod(a, x, n);
ll last = ret;
_for(i, 1, t)
{
ret = binpow(ret, ret, n);
if(ret == 1 && last != 1 && last != n - 1) return true;
last = ret;
}
if(ret != 1) return true;
return false;
}
bool Miller_Rabin(ll n)
{
if(n < 2) return false;
if(n == 2) return true;
if((n & 1) == 0) return false;
ll x = n - 1, t = 0;
while((x & 1) == 0) x >>= 1, t++;
srand(time(0));
for(int i = 0; i < S; i++)
{
ll a = rand() % (n - 1) + 1;
if(check(a, n, x, t)) return false;
}
return true;
}
ll rho(ll x, ll c)
{
ll i = 1, k = 2;
srand(time(0));
ll x0 = rand() % (x - 1) + 1;
ll y = x0;
while(1)
{
i++;
x0 = (binpow(x0, x0, x) + c) % x;
ll d = gcd(y - x0, x);
if(d != 1 && d != x) return d;
if(y == x0) return x;
if(i == k) { y = x0; k += k; }
}
}
void findfac(ll n, int k)
{
if(n == 1) return;
if(Miller_Rabin(n))
{
factor[tol++] = n;
return;
}
ll p = n;
int c = k;
while(p >= n) p = rho(p, c--);
findfac(p, k);
findfac(n / p, k);
}
vector> p;
map mp;
ll cnta[100], cnty[100];
void add(ll cur, ll cnt[])
{
rep(i, 0, p.size())
{
ll now = p[i].first, t = cur;
while(t)
{
cnt[i] += t / now;
t /= now;
}
}
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
tol = 0;
scanf("%d%lld%lld", &m, &x, &y);
_for(i, 1, m) scanf("%lld", &a[i]);
findfac(x, 107);
mp.clear(); p.clear();
rep(i, 0, tol) mp[factor[i]]++;
for(auto t: mp) p.push_back({t.first, t.second});
memset(cnta, 0, sizeof cnta);
memset(cnty, 0, sizeof cnty);
add(y, cnty);
_for(i, 1, m) add(a[i], cnta);
ll ans = 1e18;
rep(i, 0, p.size()) ans = min(ans, (cnty[i] - cnta[i]) / p[i].second);
printf("%lld\n", ans);
}
return 0;
}
这道题把树的重心考到极致
先复习一下
1.树的重心指的是以重心为根的树,所有子树的节点数的最大值最小。
要求重心可以处理出子树节点数,算出以每个节点为根的树的子树节点最大值,然后比较就行
2.树的重心到所有节点的距离和最小
3.树的重心最多也两个,若有两个一定相邻
4.两个树合并时,新的重心一定在两个重心连的链上
这道题问题其实就是合并重心,在dfs的过程中不断合并
首先重心在两个重心的链上
一个重心移动时,可以计算一下这个移动所影响的距离和的值,根据子树节点可得
这个值变小就可以移动,一直移动到极值
可以发现其中一个节点会移动到根,一个节点不会。没到根的那个就是重心
可以根据深度来区分
最后注意一下两个重心的情况就好了
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 2e5 + 10;
vector g[N];
int f[N], d[N], siz[N], ans[N], n;
void init(int u, int fa)
{
f[u] = fa;
d[u] = d[fa] + 1;
for(int v: g[u])
{
if(v == fa) continue;
init(v, u);
}
}
void dfs(int u, int fa)
{
siz[u] = 1;
ans[u] = u;
for(int v: g[u])
{
if(v == fa) continue;
dfs(v, u);
siz[u] += siz[v];
int a = ans[u], b = ans[v];
while(siz[a] < siz[u] - siz[a]) a = f[a];
while(siz[b] < siz[u] - siz[b]) b = f[b];
ans[u] = d[a] > d[b] ? a: b;
}
}
int main()
{
scanf("%d", &n);
_for(i, 1, n - 1)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
init(1, 0);
dfs(1, 0);
_for(i, 1, n)
{
int u = ans[i];
if(siz[u] != siz[i] - siz[u]) printf("%d\n", u);
else
{
int v = f[u];
if(u > v) swap(u, v);
printf("%d %d\n", u, v);
}
}
return 0;
}
用dp解决概率问题
分类讨论就行
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 1e3 + 10;
double dp[N][N];
int w, b;
double cal(int a, int b) { return (double)a / b; }
int main()
{
scanf("%d%d", &w, &b);
_for(j, 0, b) dp[0][j] = 0;
_for(i, 1, w) dp[i][0] = 1;
_for(i, 1, w)
_for(j, 1, b)
{
dp[i][j] += cal(i, i + j);
if(j >= 3) dp[i][j] += cal(j, i + j) * cal(j - 1, i + j - 1) * cal(j - 2, i + j - 2) * dp[i][j - 3];
if(j >= 2 && i >= 1) dp[i][j] += cal(j, i + j) * cal(j - 1, i + j - 1) * cal(i, i + j - 2) * dp[i - 1][j - 2];
}
printf("%.12f\n", dp[w][b]);
return 0;
}
期望dp推公式就可以了
注意几个地方
1.概率dp设计状态是顺推,期望dp是逆推
2.期望dp推公式的时候可能等式右边会出现自己,移到左边即可
3.注意期望的含义
一般是dpij = Σpi (当前步的花费 + dp……)
可以理解为dpij = Σpi * dp…… + 当前步的花费
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 1e3 + 10;
double dp[N][N];
int n, s;
int main()
{
scanf("%d%d", &n, &s);
for(int i = n; i >= 0; i--)
for(int j = s; j >= 0; j--)
{
if(i == n && j == s) continue;
double k1 = (double)i / n, k2 = (double)j / s;
dp[i][j] = (1 + k1 * (1 - k2) * dp[i][j + 1] + (1 - k1) * k2 * dp[i + 1][j]
+ (1 - k1) * (1 - k2) * dp[i + 1][j + 1]) / (1 - k1 * k2);
}
printf("%.6f\n", dp[0][0]);
return 0;
}
和上一题类似
期望dp逆推就行
注意可能停在当前地方的概率为百分百,要特判一下
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 1e3 + 10;
double dp[N][N], a[N][N], b[N][N], c[N][N];
int n, m;
int main()
{
while(~scanf("%d%d", &n, &m))
{
_for(i, 1, n)
_for(j, 1, m)
scanf("%lf%lf%lf", &a[i][j], &b[i][j], &c[i][j]);
memset(dp, 0, sizeof dp);
for(int i = n; i >= 1; i--)
for(int j = m; j >= 1; j--)
{
if(i == n && j == m) continue;
if(a[i][j] == 1) continue;
dp[i][j] = (b[i][j] * dp[i][j + 1] + c[i][j] * dp[i + 1][j] + 2) / (1 - a[i][j]);
}
printf("%.3f\n", dp[1][1]);
}
return 0;
}
把输入处理一下bfs即可
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 1e3 + 10;
const int M = 1e6 + 10;
char s[4 * N][6 * N];
int d[M], n, m, st, t;
vector g[M];
int id(int i, int j) { return (i - 1) * m + j; }
int bfs()
{
_for(i, 1, n)
_for(j, 1, m)
d[id(i, j)] = 0;
queue q;
q.push(st);
d[st] = 1;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int v: g[u])
{
if(d[v]) continue;
d[v] = d[u] + 1;
if(v == t) return d[v];
q.push(v);
}
}
return -1;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d%d", &n, &m);
getchar();
_for(i, 1, 4 * n + 3) gets(s[i] + 1);
_for(i, 1, n * m) g[i].clear();
_for(i, 1, n)
_for(j, 1, m)
{
int x, y;
if(j % 2 == 1) x = 4 * i - 1;
else x = 4 * i + 1;
y = 6 * j - 1;
if(s[x][y] == 'S') st = id(i, j);
if(s[x][y] == 'T') t = id(i, j);
if(j % 2 == 0)
{
if(s[x + 1][y + 3] == ' ') g[id(i, j)].push_back(id(i + 1, j + 1));
if(s[x + 1][y - 3] == ' ') g[id(i, j)].push_back(id(i + 1, j - 1));
if(s[x - 1][y + 3] == ' ') g[id(i, j)].push_back(id(i, j + 1));
if(s[x - 1][y - 3] == ' ') g[id(i, j)].push_back(id(i, j - 1));
if(s[x + 2][y] == ' ') g[id(i, j)].push_back(id(i + 1, j));
if(s[x - 2][y] == ' ') g[id(i, j)].push_back(id(i - 1, j));
}
else
{
if(s[x + 1][y + 3] == ' ') g[id(i, j)].push_back(id(i, j + 1));
if(s[x + 1][y - 3] == ' ') g[id(i, j)].push_back(id(i, j - 1));
if(s[x - 1][y + 3] == ' ') g[id(i, j)].push_back(id(i - 1, j + 1));
if(s[x - 1][y - 3] == ' ') g[id(i, j)].push_back(id(i - 1, j - 1));
if(s[x + 2][y] == ' ') g[id(i, j)].push_back(id(i + 1, j));
if(s[x - 2][y] == ' ') g[id(i, j)].push_back(id(i - 1, j));
}
}
printf("%d\n", bfs());
}
return 0;
}
打表可以看出来
但比赛时还是推出来的
首先题目说了没有平方因子
那对于一个数,肯定是它的所有因子选0此方或者1此方
那么肯定是前几个质数
代入公式可得答案为 n除以一个求和
n是当前要选的数
求和是因子之和
发现这个值可以递推
每次多一个质数就是乘以质数加1,因为是在前面的结果之下这个值选或者不选
那么就还剩下一个怎么约分的问题
每次分子乘一个p,分母乘p + 1
分子要和分母约分,要满足pi = pj + 1
也就是相邻的质数差1,可以发现只有2 和 3 这个可以特判一下
p + 1要和分子约分,这个可以暴力枚举p + 1的因子,看是不是分母的因子,是的话就约分
要用高精度
高精度乘以低精,除以低精度,模低精度
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
struct bignum
{
int s[10000], len;
bignum() { memset(s, 0, sizeof s); len = 0; }
void print()
{
for(int i = len; i >= 1; i--) printf("%d", s[i]);
}
};
bignum mul(bignum a, int t)
{
_for(i, 1, a.len) a.s[i] *= t;
_for(i, 1, a.len)
{
a.s[i + 1] += a.s[i] / 10;
a.s[i] %= 10;
}
while(a.s[a.len + 1])
{
a.len++;
a.s[a.len + 1] += a.s[a.len] / 10;
a.s[a.len] %= 10;
}
return a;
}
bignum div(bignum a, int t)
{
int& len = a.len;
for(int i = len; i >= 1; i--)
{
if(i - 1 >= 1) a.s[i - 1] += (a.s[i] % t) * 10;
a.s[i] /= t;
}
while(len && !a.s[len]) len--;
return a;
}
int mol(bignum a, int t)
{
int d = 0;
for(int i = a.len; i >= 1; i--)
d = (d * 10 + a.s[i]) % t;
return d;
}
bool check(int x)
{
if(x == 1 || x == 0) return false;
for(int i = 2; i * i <= x; i++)
if(x % i == 0)
return false;
return true;
}
vector p;
int main()
{
_for(i, 2, 300)
if(check(i))
p.push_back(i);
int T; scanf("%d", &T);
while(T--)
{
string s;
cin >> s;
int len = s.size();
if(s == "1")
{
puts("1/1");
continue;
}
bignum x; int t = 0;
x.len = len;
for(int i = len - 1; i >= 0; i--)
x.s[++t] = s[i] - '0';
int pos;
rep(i, 0, p.size())
{
x = div(x, p[i]);
if(!x.len) break;
pos = i;
}
vector ans;
_for(i, 0, pos) ans.push_back(p[i]);
if(ans.size() == 1)
{
puts("2/3");
continue;
}
else if(ans.size() == 2)
{
puts("1/2");
continue;
}
bignum up; up.len = 1; up.s[1] = 1;
bignum down; down.len = 1; down.s[1] = 2;
rep(i, 2, ans.size())
{
int now = p[i] + 1;
for(int j = now - 1; j >= 1; j--)
if(now % j == 0 && mol(up, j) == 0)
{
now /= j;
up = div(up, j);
break;
}
up = mul(up, p[i]);
down = mul(down, now);
}
up.print();
putchar('/');
down.print();
puts("");
}
return 0;
}
总结了一下 写在这篇博客
网络流建模技巧_Keep going, don't settle.-CSDN博客
n只有18那果断状压dp
注意每次转移的时候,两条鱼相遇还要乘上一个概率,即1 / C(m, 2) m为当前存活的鱼的数目
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
double dp[1 << 18], a[20][20];
int n;
int main()
{
scanf("%d", &n);
rep(i, 0, n)
rep(j, 0, n)
scanf("%lf", &a[i][j]);
dp[0] = 1;
rep(S, 0, 1 << n)
{
rep(i, 0, n)
if(S & (1 << i))
{
int cnt = 1;
double sum = 0;
rep(j, 0, n)
if(j != i && !(S & (1 << j)))
sum += a[j][i], cnt++;
if(cnt) dp[S] += dp[S ^ (1 << i)] * 2 / cnt / (cnt - 1) * sum;
}
}
int all = (1 << n) - 1;
rep(i, 0, n) printf("%.6f ", dp[all ^ (1 << i)]);
return 0;
}
看到b有1e9一下子懵逼了
但是考虑的时候我先不考虑1e9,先想dp
dp[i][j]表示前i位余数为j的方案数
一开始我想的是从低位开始,发现不好弄
然后我就从高位开始,就好处理很多,每次余数乘以10加上当前的数即可
可以发现每次转移都是类似的,固定的i都转移到固定的一些j
那问题来了,dp方程都写好了,怎么处理1e9
很快想到矩阵快速幂,但是之前都是优化递推式,手算矩阵的,这个是不定的,我这道题就卡在这里
看了题解后发现,构造一个矩阵A,如果余数i转化为j,那就Aij++
这样子,乘上这个矩阵就恰好完成了一次转移
我验证了一下,恰好是这样
dp的初始状态是dp[0][0] = 1
也就是这样一个矩阵[1, 0, 0, 0……]
手算可得,dp[b][k]显然就是A^b矩阵的[0][k]这个位置
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 150;
struct node
{
ll s[N][N];
node() { memset(s, 0, sizeof s); }
}A;
int n, b, k, x;
node mul(node a, node b)
{
node c;
rep(i, 0, x)
rep(j, 0, x)
rep(t, 0, x)
c.s[i][j] = (c.s[i][j] + a.s[i][t] * b.s[t][j]) % mod;
return c;
}
int main()
{
scanf("%d%d%d%d", &n, &b, &k, &x);
_for(i, 1, n)
{
int cur; scanf("%d", &cur);
rep(j, 0, x)
A.s[j][(j * 10 + cur) % x]++;
}
node res;
rep(i, 0, x) res.s[i][i] = 1;
for(; b; b >>= 1)
{
if(b & 1) res = mul(res, A);
A = mul(A, A);
}
printf("%lld\n", res.s[0][k]);
return 0;
}
独立做出
一个数为p1 ^ k1 * p2 ^ k2……
因数个数为(k1 + 1) (k2 + 1) ……
因此可以暴力将n分解成很多个因子
要使数最小,显然选前几个质数
把这些因子分配到前几个因子就可以了
注意longlong如果爆了就变成负数了
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long LL;
LL ans = 1e18;
int p[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43};
LL cal(LL a, int b)
{
LL res = 1;
_for(i, 1, b)
{
res *= a;
if(res < 0) return -1;
}
return res;
}
void dfs(int n, LL cur, int pos)
{
if(cur < 0 || cur > ans) return;
if(n == 1)
{
ans = min(ans, cur);
return;
}
for(int i = 2; i <= n; i++)
if(n % i == 0)
dfs(n / i, cur * cal(p[pos], i - 1), pos + 1);
}
int main()
{
int n;
scanf("%d", &n);
dfs(n, 1, 0);
printf("%lld\n", ans);
return 0;
}
今天兴致很高刷了很多题还做了网络流总结
最近一个感悟是,做你该做的,然后对结果不报期望
太多报很大期望结果事与愿违了。还是不报期望吧。不报期望反而没什么压力,内心平静