I - Penguins (模拟题)
直接bfs,时间复杂度O(20^4)
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 25;
const double eps = 1e-5;
bool vis[N][N][N][N];
char a[N][N], b[N][N];
int fx[4][2] = {
{1, 0},
{-1, 0},
{0, 1},
{0, -1}
};
int fxidl[4] = {2, 1, 0, 3};
int fxidr[4] = {2, 0, 1, 3};
bool check(int x,int y) {
if(x <= 0 || x > 20 || y <= 0 || y > 20) return false;
return true;
}
struct node {
int x1, y1, x2, y2;
};
node up[N][N][N][N];
int rfx[N][N][N][N];
char cfx[] = "DLRU";
bool bfs(int x1, int y1, int x2, int y2) {
queue<node> q;
q.push({x1, y1, x2, y2});
vis[x1][y1][x2][y2] = 1;
while(!q.empty()) {
node cur = q.front();
q.pop();
x1 = cur.x1, y1 = cur.y1, x2 = cur.x2, y2 = cur.y2;
if(x1 == 20 && y1 == 1 && x2 == 1 && y2 == 1) {
return true;
}
for(int i = 0; i < 4; i++) {
int f1 = fxidl[i], f2 = fxidr[i];
int nx1 = x1 + fx[f1][0], ny1 = y1 + fx[f1][1];
int nx2 = x2 + fx[f2][0], ny2 = y2 + fx[f2][1];
if(!check(nx1, ny1) || a[ny1][nx1] == '#') {nx1 = x1, ny1 = y1;}
if(!check(nx2, ny2) || b[ny2][nx2] == '#') {nx2 = x2, ny2 = y2;}
if(vis[nx1][ny1][nx2][ny2]) continue;
vis[nx1][ny1][nx2][ny2] = 1;
q.push({nx1, ny1, nx2, ny2});
up[nx1][ny1][nx2][ny2] = cur;
rfx[nx1][ny1][nx2][ny2] = i;
}
}
return false;
}
int main() {
IOS;
for(int i = 1; i <= 20; i++) {
for(int j = 1; j <= 20; j++) {
cin >> a[i][j];
}
for(int j = 1; j <= 20; j++) {
cin >> b[i][j];
}
}
up[20][20][1][20] = {0, 0, 0, 0};
bfs(20, 20, 1, 20);
vector<int> ans;
int x1 = 20, y1 = 1, x2 = 1, y2 = 1;
while(x1) {
ans.push_back(rfx[x1][y1][x2][y2]);
node u = up[x1][y1][x2][y2];
x1 = u.x1, y1 = u.y1, x2 = u.x2, y2 = u.y2;
}
ans.pop_back();
reverse(ans.begin(), ans.end());
cout << ans.size() << endl;
for(int i = 0; i < ans.size(); i++) cout << cfx[ans[i]];
cout << endl;
x1 = 20, y1 = 20, x2 = 1, y2 = 20;
a[y1][x1] = 'A';
b[y2][x2] = 'A';
for(int i = 0; i < ans.size(); i++) {
int f1 = fxidl[ans[i]], f2 = fxidr[ans[i]];
int nx1 = x1 + fx[f1][0], ny1 = y1 + fx[f1][1];
int nx2 = x2 + fx[f2][0], ny2 = y2 + fx[f2][1];
if(!check(nx1, ny1) || a[ny1][nx1] == '#') {nx1 = x1, ny1 = y1;}
if(!check(nx2, ny2) || b[ny2][nx2] == '#') {nx2 = x2, ny2 = y2;}
a[ny1][nx1] = 'A';
b[ny2][nx2] = 'A';
x1 = nx1, y1 = ny1, x2 = nx2, y2 = ny2;
}
for(int i = 1; i <= 20; i++) {
for(int j = 1; j <= 20; j++) cout << a[i][j];
cout << " ";
for(int j = 1; j <= 20; j++) cout << b[i][j];
cout << endl;
}
}
J - Product of GCDs(数学)
分别算每个质因子\(p^c\)的贡献。设\(f_{p,c}\)代表数组中至少包含\(p^c\)的数的个数,则取\(k\)个数的方案数就是\(C(f_{p,c},k)\)。从而可得取k个数的gcd恰好包含\(p^c\)的方案数数为\(C(f_{p,c},k)-C(f_{p,c+1},k)\)。故质因子\(p\)的贡献的幂为
注意上面的式子求出来的是幂,要模\(\varphi(P)\),最后直接对每个质数快速幂再累乘起来即可。使用__int128
避免使用快速乘。
这题比较卡常,要注意写法。
时间复杂度:
分解质因数暴力求\(\varphi(P)\),预处理\(\sqrt{P}\)内的质数,复杂度为\(O(\sqrt{P}+T\frac{\sqrt{P}}{log P})\)
\(O(\frac{x}{logx})\)次快速幂(即素数个数,由\(\pi(x)\sim\frac{x}{logx}\)得到)
组合数\(O(nk)\)递推
统计答案大概是\(x\log x\)级别的。
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 8e4 + 10;
const int M = 1e7 + 10;
const double eps = 1e-5;
int pri[M], cnt;
bool isnp[M];
int num[N];
ll C[40001][31];
ll getphi(ll n) {
ll p = n;
for(int i = 0; 1ll * pri[i] * pri[i] < p; i++) {
if(n % pri[i] == 0) {
p = p / pri[i] * (pri[i] - 1);
while(n % pri[i] == 0) n /= pri[i];
}
}
if(n > 1) p = p / n * (n - 1);
return p;
}
ll mul(ll x, ll y, ll m) {
return (__int128)x * y % m;
}
inline ll qpow(ll a, ll b, ll m) {
ll res = 1;
while(b) {
if(b & 1) res = mul(res, a, m);
a = mul(a, a, m);
b = b >> 1;
}
return res;
}
int main() {
IOS;
isnp[1] = 1;
for(int i = 2; i < M; i++) {
if(!isnp[i]) {
pri[cnt++] = i;
}
for(int j = 0; j < cnt && 1ll * pri[j] * i < M; j++) {
isnp[i * pri[j]] = 1;
if(i % pri[j] == 0) break;
}
}
int t;
cin >> t;
while(t--) {
memset(num, 0, sizeof num);
int n, k;
ll P;
cin >> n >> k >> P;
ll phi = getphi(P);
for(int i = 1; i <= n; i++) C[i][0] = 1;
C[1][1] = 1;
for(int i = 2; i <= n; i++) {
for(int j = 1; j <= min(k, i); j++) {
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % phi;
}
}
ll ans = 1;
for(int i = 1; i <= n; i++) {
int x;
cin >> x;
num[x]++;
}
for(int i = 0; i < cnt; i++) {
int p = pri[i];
if(p > N) break;
ll pow = 0;
for(int j = p; j < N; j = j * p) {
int c = 0;
for(int x = j; x < N; x += j) {
c += num[x];
}
if(c < k) break;
pow += C[c][k];
pow %= phi;
if(1ll * j * p >= N) break;
}
if(pow) {
ans = mul(qpow(p, pow, P), ans, P);
}
}
cout << (ll)ans << endl;
}
}
K - Stack (构造)
使用二元组(var,id),其中var从1开始递增,代表数组b的值;id从n开始递减。当数组b没有值时,var递增、id递减,然后将二元组插入栈中;当数组b的值为x时,一直弹栈到弹出的二元组var==x,此时令弹出的二元组的id修改为当前的id,将当前的id修改为x,重新插入栈中。
可以发现过程中插入的二元组始终满足题目要求。最后将二元组以var为第一关键字,id为第二关键字排序编号,就可以得到数组a了。
#include <bits/stdc++.h>
#define endl '\n'
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define mp make_pair
#define seteps(N) fixed << setprecision(N)
typedef long long ll;
using namespace std;
/*-----------------------------------------------------------------*/
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
#define INF 0x3f3f3f3f
const int N = 3e6 + 10;
const double eps = 1e-5;
typedef long long ll;
typedef pair<int, int> PII;
int b[N];
vector<PII> ans;
int res[N];
int pos[N];
bool cmp(int a, int b) {
return ans[a - 1] < ans[b - 1];
}
int main() {
IOS;
int t;
// cin >> t;
t = 1;
while(t--) {
ans.clear();
stack<PII> st;
int n, k;
cin >> n >> k;
for(int i = 1; i <= n; i++) b[i] = 0;
bool ok = true;
for(int i = 1; i <= k; i++) {
int p, x;
cin >> p >> x;
b[p] = x;
if(x <= 0) ok = false;
}
int id = n + 1;
int val = 0;
for(int i = 1; i <= n; i++) {
pos[i] = i;
if(b[i] && st.size() + 1 < b[i]) {
ok = false;
break;
} else {
id--;
if(b[i])
val = b[i];
else
val++;
PII pi{val, id};
while(!st.empty() && st.top() > pi) st.pop();
st.push(pi);
ans.push_back(pi);
// cout << pi.first << " " << pi.second << endl;
}
}
if(ok) {
sort(pos + 1, pos + 1 + n, cmp);
for(int i = 1; i <= n; i++) {
res[pos[i]] = i;
}
for(int i = 1; i <= n; i++)
cout << res[i] << " \n"[i == n];
} else
cout << -1 << endl;
}
}