2022年多校冲刺NOIP联训测试9
A.理想路径
个人认为这是最难的一道,最后还是褐的\(lxhcr\)大佬的代码,实现细节真的多
不考虑环,直接按照字典序对边排序后扫即可
如果有环,那么环上能到达的所有没访问过的点都不能到达
正解应该需要对询问离线,打树上倍增找第\(k\)个
但是数据水,即使在\(accoder\)上也只需要一个火车头就能暴力碾过去
code
#pragma GCC optimize(3)
#pragma GCC optimize(2)
#pragma GCC target("avx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn = 2005;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
int n,m,q;
vector<int> v[maxn], pth[maxn][maxn], ls;
int cnt;
bool vis[maxn],now[maxn],flag[maxn];
int root;
void dfs(int x){
vis[x] = now[x] = 1;
ls.push_back(x);
if(cnt == 0)pth[root][x] = ls;
for(int it : v[x]){
if(!vis[it]){
dfs(it);
}else if(now[it]){
for(int i = ls.size() - 1; i >= 0; --i){
if(!flag[ls[i]])flag[ls[i]] = 1, ++cnt;
if(ls[i] == it)break;
}
}
}
now[x] = 0;
cnt -= flag[x];
ls.pop_back();
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i = 1; i <= m; ++i){
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y);
}
for(int i = 1; i <= n; ++i)sort(v[i].begin(), v[i].end()),v[i].erase(unique(v[i].begin(), v[i].end()), v[i].end());
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j)vis[j] = 0;
for(int j = 1; j <= n; ++j)flag[j] = 0;
root = i;
dfs(i);
}
for(int i = 1; i <= q; ++i){
int s,t,k;
scanf("%d%d%d",&s,&t,&k);
printf("%d\n",(k > pth[s][t].size() ? -1 : pth[s][t][k - 1]));
}
return 0;
}
B. 第一题
水题,但是考场时间分配不好,没有切掉,失策失策
不难发现是求\(AB\)为完全平方数的个数
两种做法
一种枚举\(A\),去掉\(A\)的非平方因子,假设得到了\(x\),那么有\(\lfloor\sqrt \frac{n}{x}\rfloor\)个\(B\)可以贡献
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 2000005;
int n,m,t[maxn],prime[maxn],cnt,mi[maxn];
bool flag[maxn];
int main(){
scanf("%d%d",&n,&m);
int mx = max(n, m);
mi[1] = 1;
for(int i = 2; i <= mx; ++i){
if(!flag[i]){
prime[++cnt] = i;
mi[i] = i;
}
for(int j = 1; j <= cnt && prime[j] * i <= mx; ++j){
flag[i * prime[j]] = 1;
mi[i * prime[j]] = prime[j];
if(i % prime[j] == 0)break;
}
}
int ans = 0;
n = n + m - mx;
m = mx;
for(int i = 1; i <= n; ++i){
int sum = 1, now = i, ls = 1;
while(now != 1){
if(ls % mi[now] == 0)ls/=mi[now];
else ls*=mi[now];
now /= mi[now];
}
ans += sqrt(m / ls);
}
printf("%d\n",ans);
return 0;
}
另一种枚举\(A\),\(B\)的公共非平方因子,(显然是\(\mu() != 0\)的数),然后有\(\lfloor\sqrt \frac{n}{x}\rfloor \times \lfloor\sqrt \frac{m}{x}\rfloor\)个数可以贡献
code
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 2000005;
int n,m,t[maxn],prime[maxn],cnt,mu[maxn];
bool flag[maxn];
int main(){
scanf("%d%d",&n,&m);
int mx = max(n, m);
mu[1] = 1;
for(int i = 2; i <= mx; ++i){
if(!flag[i]){
prime[++cnt] = i;
mu[i] = -1;
}
for(int j = 1; j <= cnt && prime[j] * i <= mx; ++j){
flag[i * prime[j]] = 1;
if(i % prime[j] == 0)break;
mu[i * prime[j]] = -mu[i];
}
}
int ans = 0;
n = n + m - mx;
m = mx;
for(int i = 1; i <= n; ++i){
if(mu[i]){
ans += (int)sqrt(n / i) * (int)sqrt(m / i);
}
}
printf("%d\n",ans);
return 0;
}
C. 消除贫困
懒得想,直接吉司机
code
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 200005;
const int inf = 2147483647;
inline int read(){
int x = 0; char c = getchar();
while(c < '0' || c > '9')c = getchar();
do{x = (x << 3) + (x << 1) + (c ^ 48); c = getchar();}while(c >= '0' && c <= '9');
return x;
}
int n, a[maxn], q;
struct tree{
struct node{
int mi,cm;
int tmi;
}t[maxn << 2 | 1];
void push_up(int x){
int ls = x << 1, rs = x << 1 | 1;
t[x].mi = min(t[ls].mi, t[rs].mi);
t[x].cm = min(t[ls].cm, t[rs].cm);
if(t[ls].mi < t[x].cm && t[ls].mi != t[x].mi)t[x].cm = t[ls].mi;
if(t[rs].mi < t[x].cm && t[rs].mi != t[x].mi)t[x].cm = t[rs].mi;
}
void built(int x, int l, int r){
if(l == r){
t[x].mi = a[l];
t[x].cm = inf;
return;
}
int mid = (l + r) >> 1;
built(x << 1, l, mid);
built(x << 1 | 1, mid + 1, r);
push_up(x);
}
void push_down(int x){
int ls = x << 1, rs = x << 1 | 1;
if(t[ls].mi < t[x].tmi){
t[ls].mi = t[x].tmi;
t[ls].tmi = t[x].tmi;
}
if(t[rs].mi < t[x].tmi){
t[rs].mi = t[x].tmi;
t[rs].tmi = t[x].tmi;
}
t[x].tmi = 0;
}
void cmax(int x, int l, int r, int val){
if(t[x].mi >= val)return;
if(t[x].cm > val){
t[x].mi = val;
t[x].tmi = val;
return;
}
if(t[x].tmi)push_down(x);
int mid = (l + r) >> 1;
cmax(x << 1, l, mid, val);
cmax(x << 1 | 1, mid + 1, r, val);
push_up(x);
}
void modify(int x, int l, int r, int pos, int val){
if(l == r){
t[x].mi = val;
t[x].cm = inf;
return;
}
if(t[x].tmi)push_down(x);
int mid = (l + r) >> 1;
if(pos <= mid)modify(x << 1, l, mid, pos, val);
else modify(x << 1 | 1, mid + 1, r, pos, val);
push_up(x);
}
void print(int x, int l, int r){
if(l == r){
printf("%d ",t[x].mi);
return;
}
if(t[x].tmi) push_down(x);
int mid = (l + r) >> 1;
print(x << 1, l, mid);
print(x << 1 | 1, mid + 1, r);
}
}t;
int main(){
n = read();
for(int i = 1; i <= n; ++i)a[i] = read();
t.built(1, 1, n);
q = read();
for(int i = 1; i <= q; ++i){
int op = read();
if(op == 1){
int p = read(), x = read();
t.modify(1, 1, n, p, x);
}else{
int x = read();
t.cmax(1, 1, n, x);
}
}
t.print(1, 1, n);
return 0;
}
D. 数串
简单的数位\(DP\),但是,模数呢?????
本题考点在于高精,以及卡常众所周知,accoders自带大常数
还有不要卡着空间上界开数组!!!!!!!
本机极限数据在\(0.4s\)左右交上去才能切。。。。。
做法没啥好说的,但是压位高精+极限卡常是真的\(nb\)
code
#pragma GCC optimize(3)
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
const ull base = 1e18;
struct big{
ull a[60];
big(){memset(a, 0, sizeof(a));}
friend big operator + (const big &a, const big &b){
if(a.a[0] == 0)return b;
if(b.a[0] == 0)return a;
big c; c.a[0] = max(a.a[0], b.a[0]);
for(register int i = 1; i <= c.a[0]; ++i)c.a[i] += a.a[i] + b.a[i];
for(register int i = 1; i <= c.a[0]; ++i){
c.a[i + 1] += c.a[i] / base;
c.a[i] = c.a[i] % base;
}
if(c.a[c.a[0] + 1])++c.a[0];
return c;
}
big operator *= (int b){
for(register int i = 1; i <= a[0]; ++i)a[i] = a[i] * b;
for(register int i = 1; i <= a[0]; ++i){
a[i + 1] += a[i] / base;
a[i] %= base;
}
if(a[a[0] + 1])++a[0];
while(a[a[0]]==0 && a[0] > 1)--a[0];
return *this;
}
big operator += (const big &b){
a[0] = max(a[0], b.a[0]);
for(register int i = 1; i <= a[0]; ++i)a[i] = a[i] + b.a[i];
for(register int i = 1; i <= a[0]; ++i){
a[i + 1] += a[i] / base;
a[i] %= base;
}
if(a[a[0] + 1])++a[0];
return *this;
}
void print(){
printf("%llu",a[a[0]]);
if(a[0])for(register int i = a[0] - 1; i; --i)printf("%018llu",a[i]);
printf("\n");
}
void clear(){
memset(a, 0, sizeof(a));
}
};
int r[15];
int n, m, k;
big ans1,ans2;
big cnt[2][1029], sum[2][1029], lj;
int main(){
scanf("%d%d%d",&n,&m,&k);
for(register int i = 1; i <= m; ++i){
int a, b; scanf("%d%d",&a,&b);
r[b] = r[b] | (1 << (a - 1));
}
int mx = 1 << k;
for(register int i = 1; i <= k; ++i){
int zt = (1 << (i - 1));
cnt[1][zt].a[1] = 1;
cnt[1][zt].a[0] = 1;
sum[1][zt].a[1] = i;
sum[1][zt].a[0] = 1;
}
for(register int pos = 1; pos < n; ++pos){
for(register int zt = 0; zt < mx; ++zt){
int now = pos & 1;
if(cnt[now][zt].a[0]){
sum[now][zt] *= 10;
lj.clear();
for(register int j = 1; j <= k; ++j){
lj += cnt[now][zt];
if(!(r[j] & zt)){
int nzt = zt | (1 << (j - 1));
cnt[1 - now][nzt] += cnt[now][zt];
sum[1 - now][nzt] += sum[now][zt] + lj;
}
}
cnt[now][zt].clear();
sum[now][zt].clear();
}
}
}
int an = n & 1;
for(register int i = 0; i < mx; ++i){
ans1 += cnt[an][i];
ans2 += sum[an][i];
}
ans1.print();
ans2.print();
return 0;
}