2019 ACM - ICPC 全国邀请赛(西安)题解(9 / 13)
The 2019 ACM-ICPC China Shannxi Provincial Programming Contest
目录
- The 2019 ACM-ICPC China Shannxi Provincial Programming Contest
- A. Tasks
- B. Product
- C. Angel's Journey
- D. Miku and Generals
- E. Tree
- I. Cracking Password
- J. And And And
- L. Swap
- M. Travel
VP地址:https://www.jisuanke.com/contest/21482/rank?page=1
A. Tasks
Solution
直接贪心即可。
Code
#include <bits/stdc++.h>
using namespace std;int a[105];int main()
{int n,m;scanf("%d%d",&n,&m);for(int i = 0;i < n;++i){scanf("%d",&a[i]);}sort(a,a+n);int cnt = 0;for(int i = 0;i < n;++i){if(m >= a[i]){cnt++;m -= a[i];}}printf("%d\n",cnt); return 0;
}
B. Product
Solution
直接推柿子,然后杜教筛即可。
Code
#include <bits/stdc++.h>using namespace std;
const int N = 2587401;
typedef long long ll;
#define int long long#define mult(x, y) (1ll * x * y >= mod ? 1ll * x * y % mod : 1ll * x * y)
#define minus(x, y) (1ll * x - y < 0 ? 1ll * x - y + mod : 1ll * x - y)
#define plus(x, y) (1ll * x + y >= mod ? 1ll * x + y - mod : 1ll * x + y)
#define ck(x) (x >= mod : x - mod : x)ll n, m, p, mod;
ll primes[N], cnt;
bool vis[N];
ll d[N], num[N];
ll phi[N];unordered_map<ll, ll> sum_phi;
unordered_map<ll, ll> sum_xdx;ll qpow(ll a, ll b, ll mod)
{ll res = 1;while(b) {if(b & 1) res = res * a % mod;a = a * a % mod;b >>= 1;}return res;
}void init(ll n)
{d[1] = 1;vis[0] = vis[1] = 1;phi[1] = 1;for(int i = 2; i <= n; ++ i) {if(vis[i] == 0) {primes[ ++ cnt] = i;phi[i] = i - 1;d[i] = 2, num[i] = 1;}for(int j = 1; j <= cnt && i * primes[j] <= n; ++ j) {vis[i * primes[j]] = 1;if(i % primes[j] == 0) {phi[i * primes[j]] = phi[i] * primes[j];num[i * primes[j]] = num[i] + 1;d[i * primes[j]] = d[i] / num[i * primes[j]] * (num[i * primes[j]] + 1) % mod;break; }phi[i * primes[j]] = phi[i] * phi[primes[j]];num[i * primes[j]] = 1;d[i * primes[j]] = (d[i] * 2) % mod;}}for(int i = 1; i <= n; ++ i) {phi[i] = plus(phi[i], phi[i - 1]);d[i] = 1ll * d[i] * i % mod;d[i] = plus(1ll * d[i], d[i - 1]);}
}inline int g_sum(ll x)
{return x;
}inline ll get_sum_phi(ll x)
{if(x <= N - 7) return phi[x];if(sum_phi.find(x) != sum_phi.end()) return sum_phi[x];ll ans = 1ll * x * (1ll * x + 1) / 2;for(ll l = 2, r; l <= x;l = r + 1) {r = x / (x / l);ans -= 1ll * (g_sum(r) - g_sum(l - 1)) * get_sum_phi(x / l);}return sum_phi[x] = ans / g_sum(1);
}inline ll get_sum_xdx(ll x)
{if(x <= N - 7) return d[x];if(sum_xdx.find(x) != sum_xdx.end()) return sum_xdx[x];ll ans = 0;for(ll l = 1, r; l <= x; l = r + 1) {r = x / (x / l);ans = (ans + 1ll * ((1ll * x / l + 1) * (1ll * x / l) / 2) % mod * ((1ll * r - l + 1) * (l + r) / 2) % mod) % mod;}return sum_xdx[x] = ans;
}ll solve()
{ll res = 0;for(ll l = 1, r; l <= n; l = r + 1) {r = n / (n / l);res = (res + (get_sum_xdx(r) - get_sum_xdx(l - 1) + mod) % mod * get_sum_phi(n / l)) % mod;}res = plus(res, res) % mod;//res = minus(res, get_sum_xdx(n));
// cout << get_sum_xdx(n) << endl;//cout << (res - get_sum_xdx(n) + mod) % mod << endl;//res = res - get_sum_xdx(n);return (res - get_sum_xdx(n) + mod) % mod;
}signed main()
{scanf("%lld%lld%lld", &n, &m, &p);mod = p - 1;init(N - 7);ll b = solve();printf("%lld\n", qpow(m, b, p));return 0;
}
C. Angel’s Journey
Solution
实际上就是求点到圆上一点的最短距离。判断一下,求切线然后计算距离即可。
Code
#include <bits/stdc++.h>
#define LL long long
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
#define PI 3.1415926535897932384626
#define EXIT exit(0);
#define DEBUG puts("Here is a BUG");
#define CLEAR(name, init) memset(name, init, sizeof(name))
const double eps = 1e-6;
const int MAXN = (int)1e9 + 5;
using namespace std; #define Vector Point #define ChongHe 0
#define NeiHan 1
#define NeiQie 2
#define INTERSECTING 3
#define WaiQie 4
#define XiangLi 5 int dcmp(double x) { return fabs(x) < eps ? 0 : (x < 0 ? -1 : 1); } struct Point { double x, y; Point(const Point& rhs): x(rhs.x), y(rhs.y) { } //拷贝构造函数 Point(double x = 0.0, double y = 0.0): x(x), y(y) { } //构造函数 friend istream& operator >> (istream& in, Point& P) { return in >> P.x >> P.y; } friend ostream& operator << (ostream& out, const Point& P) { return out << P.x << ' ' << P.y; } friend Vector operator + (const Vector& A, const Vector& B) { return Vector(A.x+B.x, A.y+B.y); } friend Vector operator - (const Point& A, const Point& B) { return Vector(A.x-B.x, A.y-B.y); } friend Vector operator * (const Vector& A, const double& p) { return Vector(A.x*p, A.y*p); } friend Vector operator / (const Vector& A, const double& p) { return Vector(A.x/p, A.y/p); } friend bool operator == (const Point& A, const Point& B) { return dcmp(A.x-B.x) == 0 && dcmp(A.y-B.y) == 0; } friend bool operator < (const Point& A, const Point& B) { return A.x < B.x || (A.x == B.x && A.y < B.y); } void in(void) { scanf("%lf%lf", &x, &y); } void out(void) { printf("%lf %lf", x, y); }
}; struct Line { Point P; //直线上一点 Vector dir; //方向向量(半平面交中该向量左侧表示相应的半平面) double ang; //极角,即从x正半轴旋转到向量dir所需要的角(弧度) Line() { } //构造函数 Line(const Line& L): P(L.P), dir(L.dir), ang(L.ang) { } Line(const Point& P, const Vector& dir): P(P), dir(dir) { ang = atan2(dir.y, dir.x); } bool operator < (const Line& L) const { //极角排序 return ang < L.ang; } Point point(double t) { return P + dir*t; }
}; typedef vector<Point> Polygon; struct Circle { Point c; //圆心 double r; //半径 Circle() { } Circle(const Circle& rhs): c(rhs.c), r(rhs.r) { } Circle(const Point& c, const double& r): c(c), r(r) { } Point point(double ang) const { return Point(c.x + cos(ang)*r, c.y + sin(ang)*r); } //圆心角所对应的点 double area(void) const { return PI * r * r; }
}; double Dot(const Vector& A, const Vector& B) { return A.x*B.x + A.y*B.y; } //点积
double Length(const Vector& A){ return sqrt(Dot(A, A)); } //向量长度
double Angle(const Vector& A, const Vector& B) { return acos(Dot(A, B)/Length(A)/Length(B)); } //向量夹角
double Cross(const Vector& A, const Vector& B) { return A.x*B.y - A.y*B.x; } //叉积
double Area(const Point& A, const Point& B, const Point& C) { return fabs(Cross(B-A, C-A)); } // 有向面积AC 在 AB逆时针方向bool isCollinear(Point A, Point B, Point C) { return dcmp(Cross(B-A, C-B)) == 0; }//三点共线判定 Vector Rotate(const Vector& A, const double& rad) { return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad)); } //向量绕起点旋转Vector Normal(const Vector& A) { //向量的单位法线double len = Length(A); return Vector(-A.y / len, A.x / len);
} double disP2P(Point A, Point B)
{return sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
}
int getTangents(const Point& P, const Circle& C, std::vector<Line>& L) { Vector u = C.c - P; double dis = Length(u); if (dcmp(dis - C.r) < 0) return 0; if (dcmp(dis - C.r) == 0) { L.push_back(Line(P, Rotate(u, PI / 2.0))); return 1; } double ang = asin(C.r / dis); L.push_back(Line(P, Rotate(u, ang))); L.push_back(Line(P, Rotate(u, -ang))); return 2;
}
int GetLineCircleIntersection(Line& L, const Circle& C, vector<Point>& sol) { double t1, t2; double a = L.dir.x, b = L.P.x - C.c.x, c = L.dir.y, d = L.P.y - C.c.y; double e = a*a + c*c, f = 2.0*(a*b + c*d), g = b*b + d*d - C.r*C.r; double delta = f*f - 4*e*g; //判别式 if (dcmp(delta) < 0) return 0; //相离 if (dcmp(delta) == 0) { //相切 t1 = t2 = -f / (2 * e); sol.push_back(L.point(t1)); return 1; } t1 = (-f - sqrt(delta)) / (2.0 * e); sol.push_back(L.point(t1)); // 相交 t2 = (-f + sqrt(delta)) / (2.0 * e); sol.push_back(L.point(t2)); return 2;
}
void solve()
{double rx,ry,r;scanf("%lf%lf%lf",&rx,&ry,&r);double x,y;scanf("%lf%lf",&x,&y);double res = 0;if(x < rx + r && x > rx - r){Circle c(Point(rx,ry),r);Point st(x,y);vector<Line> Qies;getTangents(st,c,Qies);res = 2e18;for(int i = 0;i < 2;++i){vector<Point> ps;if(GetLineCircleIntersection(Qies[i],c,ps) == 0) {continue;};Point O = c.c;Point A = ps[0];Point B(rx,ry-r);double ang = acos(Dot(A-O,B-O)/r/r);res = min(res, disP2P(st,ps[0]) + ang * r);ang = acos(Dot(B-O,A-O)/r/r);res = min(res, disP2P(st,ps[0]) + ang * r);}}else{if(dcmp(x - rx - r) >= 0){res = disP2P({x,y},{rx + r, ry}) + PI * r / 2;}else{res = disP2P({x,y},{rx - r, ry}) + PI * r / 2;}}printf("%.4lf\n",res);
}int main()
{int t;scanf("%d",&t);while(t--){solve();}}
D. Miku and Generals
Solution
构造二分图,然后直接DP即可。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 202;
const int M = 100005;
bool dp[N][M*2];
int a[N];
int n,m;
vector<int> edge[N];
int vis[N];
int ca,cb;void dfs(int now)
{if(vis[now]==1)ca += a[now];else cb += a[now];for(auto &x:edge[now]){if(!vis[x]){if(vis[now]==1)vis[x]=2;else vis[x]=1;dfs(x);}}
}void solve()
{memset(dp,0,sizeof(dp));memset(vis,0,sizeof(vis));int sum = 0;scanf("%d%d",&n,&m);for(int i = 1;i <= n;++i){scanf("%d",&a[i]);a[i] /= 100;sum += a[i];}for(int i = 1;i <= n;++i){edge[i].clear();}for(int i = 1,a,b;i <= m;++i){scanf("%d%d",&a,&b);edge[a].push_back(b);edge[b].push_back(a);}dp[0][M] = 1;int cnt = 0;for(int i = 1;i <= n;++i){if(!vis[i]){cnt++;ca = cb = 0;vis[i] = 1;dfs(i);int res1 = ca-cb;int res2 = cb-ca;for(int j = 0;j <= 2*M;++j){if(j + res1 <= 2*M&&j + res1 >= 0){dp[cnt][j] |= dp[cnt-1][j+res1];}if(j + res2 <= 2*M&&j + res2 >= 0){dp[cnt][j] |= dp[cnt-1][j+res2];}}}}int ans = -1;for(int i = M;i <= 2*M;++i){if(dp[cnt][i]){ans = (sum+(i-M))/2;break;}}ans *= 100;printf("%d\n",ans);
}int main()
{int t;scanf("%d",&t);while(t--){solve();}return 0;
}
E. Tree
Solution
直接暴力树链剖分即可,时限10s,复杂度没问题。
Code
#include <bits/stdc++.h>
using namespace std;const int maxn = 1e5+5;vector<int> edge[maxn];
int top[maxn],dfn[maxn],rnk[maxn],dfn_clock;
int size[maxn],son[maxn],fa[maxn];
int a[maxn];void dfs(int now,int pre)
{fa[now] = pre;size[now] = 1;for(auto &x:edge[now]){if(x==pre)continue;dfs(x,now);size[now] += size[x];if(size[x] > size[son[now]])son[now] = x;}
}
void dfs2(int now,int tp)
{top[now] = tp;dfn[now] = ++dfn_clock;rnk[dfn_clock] = now;if(son[now])dfs2(son[now],tp);for(auto &x:edge[now]){if(x == fa[now]||x == son[now])continue;dfs2(x,x);}
}struct Segment_tree
{int cnt[maxn<<2],add[maxn<<2];void build(int root,int l,int r,int o){if(l == r){cnt[root] = (a[rnk[l]]>>o)&1;return;}int mid = l+r>>1;build(root<<1,l,mid,o);build(root<<1|1,mid+1,r,o);cnt[root] = cnt[root<<1]+cnt[root<<1|1];}void pushdown(int root,int l,int r){if(add[root]){int mid = l+r>>1;if(add[root]==-1){add[root<<1] = -1;add[root<<1|1] = -1;cnt[root<<1] = 0;cnt[root<<1|1] = 0;add[root] = 0;}else {add[root<<1] = 1;add[root<<1|1] = 1;cnt[root<<1] = mid-l+1;cnt[root<<1|1] = r-mid;add[root] = 0;}}}void modify(int root,int l,int r,int ql,int qr,int opt){if(l >= ql&&r <= qr){if(opt==0){cnt[root] = 0;add[root] = -1;return;}else{cnt[root] = r-l+1;add[root] = 1;return;}}int mid = l+r>>1;pushdown(root,l,r);if(ql <= mid)modify(root<<1,l,mid,ql,qr,opt);if(qr > mid)modify(root<<1|1,mid+1,r,ql,qr,opt);cnt[root] = cnt[root<<1]+cnt[root<<1|1];}int query(int root,int l,int r,int ql,int qr){if(l >= ql&&r <= qr)return cnt[root];int mid = l+r>>1;pushdown(root,l,r);int ans = 0;if(ql <= mid)ans += query(root<<1,l,mid,ql,qr);if(qr > mid)ans += query(root<<1|1,mid+1,r,ql,qr);return ans;}
}sg[33];int main()
{int n,q;scanf("%d%d",&n,&q);for(int i = 1;i <= n;++i)scanf("%d",&a[i]);for(int i = 1,a,b;i < n;++i){scanf("%d%d",&a,&b);edge[a].push_back(b);edge[b].push_back(a);}dfs(1,0),dfs2(1,1);for(int i = 0;i <= 29;++i){sg[i].build(1,1,n,i);}while(q--){static int opt,s,t;scanf("%d%d%d",&opt,&s,&t);if(opt==1){for(int i = 0;i <= 29;++i){if(t>>i&1){int x = s;while(top[x]!=1){sg[i].modify(1,1,n,dfn[top[x]],dfn[x],1);x = fa[top[x]];}sg[i].modify(1,1,n,dfn[1],dfn[x],1);}}}else if(opt==2){for(int i = 0;i <= 29;++i){int x = s;if(t>>i&1)continue;while(top[x]!=1){sg[i].modify(1,1,n,dfn[top[x]],dfn[x],0);x = fa[top[x]];}sg[i].modify(1,1,n,dfn[1],dfn[x],0);}}else{bool ok = false;int ans = 0;for(int i = 0;i <= 29;++i){int x = s;int cnt = 0;while(top[x]!=1){cnt += sg[i].query(1,1,n,dfn[top[x]],dfn[x]);x = fa[top[x]];}cnt += sg[i].query(1,1,n,dfn[1],dfn[x]);if(cnt&1){ok = true;ans += 1<<i;}}if(ans==t)ok = 1;else ok = 0;if(!ok)printf("YES\n");else printf("NO\n");}}return 0;}
I. Cracking Password
Problem
给定一个长度为 nnn 的序列,b1⋯bnb_1\cdots b_nb1⋯bn,其中 b1=akmodp,b2=ak+1modp,⋯,bn=ak+n−1modpb_1=a^k\mod p,b_2=a^{k+1}\mod p,\cdots,b_n=a^{k+n-1}\mod pb1=akmodp,b2=ak+1modp,⋯,bn=ak+n−1modp。请你计算 a,pa, pa,p 的值,若有多解,输出 unsure
, 若无解,输出 error
,否则输出 aaa 和 ppp 。
bi≤105,p≤1010b_i\le 10^5,p\le10^{10}bi≤105,p≤1010
Solution
给出的是一个等比数列,公比为 aaa,注意这里给定的数列在 mod p\ \text{mod}\ p mod p 意义下是等比数列,也就意味着有两种情况:
本身就是 ak,ak+1,ak+2⋯a^k,a^{k+1},a^{k+2}\cdotsak,ak+1,ak+2⋯ 的等比数列,有没有模数均可。
本身不是 ak,ak+1,ak+2⋯a^k,a^{k+1},a^{k+2}\cdotsak,ak+1,ak+2⋯ 的等比数列,模上特殊的模数之后变为权值为 ak,ak+1,ak+2⋯a^k,a^{k+1},a^{k+2}\cdotsak,ak+1,ak+2⋯ 的等比数列。
为了验证该数列为等比数列,我们可以找一些等比数列特有的性质,来予以验证。
显然对于一个等比数列,有性质:等比中项,即 bi2=bi−1bi+1b_i^{\ 2}=b_{i-1}b_{i+1}bi 2=bi−1bi+1 。
对于上面提到的两种情况,整个序列的 i∈[2,n−1]i\in [2,n-1]i∈[2,n−1],均有:
bi2modp=bi−1bi+1modpbi2≡bi−1bi+1modpbi2−bi−1bi+1≡0modp\begin{aligned}b_i^{\ 2}\mod p=b_{i-1}b_{i+1}\mod p\\b_i^{\ 2}\equiv b_{i-1}b_{i+1}\mod p\\b_i^{\ 2}-b_{i-1}b_{i+1}\equiv0 \mod p\end{aligned}bi 2modp=bi−1bi+1modpbi 2≡bi−1bi+1modpbi 2−bi−1bi+1≡0modp
显然有 p∣bi2−bi−1bi+1p\ | \ b_i^{\ 2}-b_{i-1}b_{i+1}p ∣ bi 2−bi−1bi+1。
因此 ppp 一定是 gcd{bi2−bi−1bi+1},i∈[2,n−1]gcd\{b_i^{\ 2}-b_{i-1}b_{i+1}\},i\in [2,n-1]gcd{bi 2−bi−1bi+1},i∈[2,n−1] 的质因子。
通过分析我们可以发现显然 aaa 为定值,我们只需要枚举 gcd{bi2−bi−1bi+1},i∈[2,n−1]gcd\{b_i^{\ 2}-b_{i-1}b_{i+1}\},i\in [2,n-1]gcd{bi 2−bi−1bi+1},i∈[2,n−1] 的所有质因子,判断该质因子是否合法即可。
为了检验该质因子模数合法,我们可以使用该模数求出模 ppp 意义下的 aaa 的值,即 a=ak+1akmodp=ak+1×inv(ak)modpa=\cfrac{a^{k+1}}{a^k}\mod p=a^{k+1}\times inv(a^k) \mod pa=akak+1modp=ak+1×inv(ak)modp,使用当前枚举到的模数 ppp 计算出 aaa 以后,我们可以使用 BSGS\tt BSGSBSGS 算法求出 ax≡akmodpa^x\equiv a^k\mod pax≡akmodp(ak=b1a^k=b_1ak=b1)是否有解,有解的话再分别验证一个整个序列 ak,ak+1,ak+2⋯a^k,a^{k+1},a^{k+2}\cdotsak,ak+1,ak+2⋯ 是否均可使用 ak×aa^k\times aak×a 推导出来即可。
那么对于上面提到的两种情况:
第一种情况,显然对于所有的 bi2=bi−1bi+1b_i^{\ 2}=b_{i-1}b_{i+1}bi 2=bi−1bi+1 计算出的结果均为 000,即 gcd{bi2−bi−1bi+1}=0,i∈[2,n−1]gcd\{b_i^{\ 2}-b_{i-1}b_{i+1}\}=0,i\in [2,n-1]gcd{bi 2−bi−1bi+1}=0,i∈[2,n−1]。显然此时所有大于 ak+n−1a^{k+n-1}ak+n−1 的模数均为合法的答案,输出 unsure
即可。
第二种情况,若整个序列 b1=b2=b3⋯=bnb_1=b_2=b_3\cdots=b_nb1=b2=b3⋯=bn,显然计算出的 gcd{bi2−bi−1bi+1}=0,i∈[2,n−1]gcd\{b_i^{\ 2}-b_{i-1}b_{i+1}\}=0,i\in [2,n-1]gcd{bi 2−bi−1bi+1}=0,i∈[2,n−1] 同样为 000,此时若 b1=b2=b3⋯=bn=1b_1=b_2=b_3\cdots=b_n=1b1=b2=b3⋯=bn=1,则有多解,输出 unsure
即可。否则显然,尽管序列是一个等比数列,但是不是值为 ak,ak+1,ak+2⋯a^k,a^{k+1},a^{k+2}\cdotsak,ak+1,ak+2⋯ 的等比数列,故无解输出 error
即可。
其余的情况使用上面的方法计算 aaa 和 ppp 即可。若没有答案输出 error
,若有多解输出 unsure
,若仅有一解,使用该模数计算 aaa ,然后输出 a,pa,pa,p 即可。
最后再特判一下 n == 1
以及 n == 2
即可。
Hint
注意 p≤1010p\le 10^{10}p≤1010,所以 BSGS\tt BSGSBSGS 的时候要强转成 __int128
,否则会爆 long long
。
我的 BSGS\tt BSGSBSGS 模板里的
if(1 % p == b % p) return 0;
这里的意思是解为 000 啊,不是无解…抄模板的时候这儿忘了改了,因为这个疯狂wa…
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e5 + 7; int n, m;
int b[N];
int p;
vector<int> mods;
vector<int> ans;
int maxx;int qpow(int a, int b, int mod)
{int res = 1;while(b) {if(b & 1) res = (__int128)res * a % mod;a = (__int128)a * a % mod;b >>= 1;}return res;
}int inv(int x, int mod)
{return qpow(x, mod - 2, mod);
}bool BSGS(int a, int b, int p)
{if(1 % p == b % p) return true;int k = sqrt(p) + 1;unordered_map<int, int> Hash;for(int i = 0, j = b % p; i < k; ++ i) {Hash[j] = i;j = (__int128) j * a % p;}int ak = 1;for(int i = 0; i < k; ++ i) ak = (__int128) ak * a % p;for(int i = 1, j = ak; i <= k; ++ i) {if(Hash.count(j)) return true;j = (__int128) j * ak % p;}return false;
}bool check(int p)
{if(maxx >= p) return 0;int a = b[2] * inv(b[1], p) % p;if(BSGS(a, b[2], p) == 0) return 0;int now = b[1];for(int i = 2; i <= n; ++ i) {now = now * a % p;if(now != b[i]) return 0;}return 1;
}signed main()
{scanf("%lld", &n);for(int i = 1; i <= n; ++ i) {scanf("%lld", &b[i]);maxx = max(maxx, b[i]); } if(n == 1) return 0, puts("unsure"); if(n == 2) {if(b[1] == b[2] && b[1] != 1) return 0, puts("error");else return 0, puts("unsure");} int gcd = 0;for(int i = 2; i <= n - 1; ++ i) {gcd = __gcd(gcd, abs(b[i] * b[i] - b[i - 1] * b[i + 1]));} if(gcd == 0) { bool same = 1; for(int i = 2; i <= n; ++ i) {if(b[i] != b[i - 1]) {same = 0;}if(same) {if(b[1] == 1) return 0, puts("unsure");else return 0, puts("error");}} return 0, puts("unsure");}for(int i = 2; i * i <= gcd; ++ i) {if(gcd % i == 0) {mods.push_back(i);while(gcd % i == 0) {gcd /= i;}}}if(gcd > 1) mods.push_back(gcd);for(int i = 0; i < mods.size(); ++ i) {if(check(mods[i]))ans.push_back(mods[i]);}if(ans.size() == 0) {puts("error");}else if(ans.size() > 1) puts("unsure");else {int a = b[2] * inv(b[1], ans[0]) % ans[0];printf("%lld %lld\n", a, ans[0]);}return 0;
}
J. And And And
Solution
直接树上启发式合并即可。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int,ll> ;
const int maxn = 1e5+5;
const int mod = 1e9+7;
vector<pii> edge[maxn];
map<ll,ll> mp;
ll ans;
ll val[maxn];
int size[maxn],dfn[maxn],rnk[maxn],dfn_clock,son[maxn];
int n;
void dfs(int now)
{size[now] = 1;dfn[now] = ++dfn_clock;rnk[dfn_clock] = now;for(auto &x:edge[now]){val[x.first] = val[now]^x.second;dfs(x.first);size[now] += size[x.first];if(size[x.first] > size[son[now]])son[now] = x.first;}
}void dfs(int now,bool flag)
{for(auto &x:edge[now]){if(x.first!=son[now])dfs(x.first,0);}if(son[now])dfs(son[now],1);if(son[now])ans += (n-size[son[now]])*mp[val[now]]%mod;ans %= mod;for(auto &q:edge[now]){int x = q.first;if(x==son[now])continue;for(int j = dfn[x];j <= dfn[x]+size[x]-1;++j){int y = rnk[j];ll need = val[y];ans += 1ll*size[y]*mp[need]%mod;ans %= mod;}for(int j = dfn[x];j <= dfn[x]+size[x]-1;++j){int y = rnk[j];if(val[y] == val[now])ans += 1ll*(n-size[x])*size[y]%mod;mp[val[y]] += size[y];ans %= mod;}}mp[val[now]] += size[now];if(!flag)mp.clear();
}int main()
{scanf("%d",&n);for(int i = 2;i <= n;++i){int x;ll b;scanf("%d%lld",&x,&b);edge[x].push_back(make_pair(i,b));}dfs(1);dfs(1,1);cout<<ans%mod<<endl;return 0;
}
L. Swap
Solution
答案显然就是置换群循环节长度乘2,因为这两种操作,同一种操作使用两次就会恢复原状,那么我们对原序列分别进行一次这两种操作以后,找出这两种置换操作的置换群的循环节的长度 xxx,其中整个置换群循环节长度即为每个置换循环节长度的 lcm\text{lcm}lcm,直接暴力模拟计算每个循环节的长度即可。循环节长度意义就是我们经过 xxx 次置换操作之后就会回到原序列,即不同排列的种数。
Code
#include <bits/stdc++.h>using namespace std;
const int N = 1e5 + 7;
int n, m;
int a[N];
bool vis[N];void solve()
{int mid = (n + 1) >> 1;for(int i = 1; i <= mid; ++ i) {if(n & 1 && i == mid) continue; swap(a[i], a[i + mid]);}for(int i = 1; i <= n; ++ i) {if(!(i & 1)) {swap(a[i], a[i - 1]);}}int len = 1;for(int i = 1; i <= n; ++ i) { int now = i;int cnt = 0;while(vis[now] == 0) {cnt ++ ;vis[now] = 1;now = a[now];}if(cnt == 0) continue;len = len * cnt / __gcd(len, cnt);}cout << len * 2 << endl;
}int main()
{scanf("%d", &n);for(int i = 1; i <= n; ++ i) {scanf("%d", &a[i]);}for(int i = 1; i <= n; ++ i) {a[i] = i;} if(n == 1) {puts("1");return 0;}solve();return 0;
}
M. Travel
Solution
显然直接二分升级的次数,每次 O(n)O(n)O(n) bfs
判断即可。
Code
#include <bits/stdc++.h>
using namespace std;const int N = 1e5 + 10;
vector<pair<int,int>> son[N];
int c,d,e;
int vis[N];
int dis[N];bool bfs(int s, int t, int mid)
{memset(dis,0,sizeof(dis));memset(vis,0,sizeof(vis));long long lim = 1ll * d * mid;queue<int> q;q.push(s);vis[s] = 1;while(q.size()){int u = q.front();q.pop();for(int i = 0;i < son[u].size();++i){int v = son[u][i].first;int cost = son[u][i].second;if(!vis[v] && cost <= lim){dis[v] = dis[u] + 1;vis[v] = 1;q.push(v);}}}return vis[t] && dis[t] <= 1ll * e * mid;
}int main()
{int n,m;scanf("%d%d",&n,&m);scanf("%d%d%d",&c,&d,&e);for(int i = 0;i < m;++i){int u,v,w;scanf("%d%d%d",&u,&v,&w);son[u].push_back({v,w});son[v].push_back({u,w});}int l = 1,r = 1e6;int res = 0;while(l <= r){int mid = l + r >> 1;if(bfs(1,n,mid)){r = mid - 1;res = mid;}else l = mid + 1;}printf("%lld\n", 1ll * c * res);return 0;
}
2019 ACM - ICPC 全国邀请赛(西安)题解(9 / 13)相关推荐
- 2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 The 2019 ICPC China Nanchang National Invitation ...
- 2019 ACM/ICPC 全国邀请赛(西安)J And And And (树DP+贡献计算)
Then n - 1n−1 lines follow. ii-th line contains two integers f_{a_i}(1 \le f_{a_i} < i)fai(1≤fa ...
- 2019 ACM - ICPC 西安邀请赛 B. Product (杜教筛) 简单数论(bushi)
G.(2019 ACM/ICPC 全国邀请赛(西安)B) Product Weblink https://nanti.jisuanke.com/t/39269 Problem && S ...
- 2019 ICPC全国邀请赛(西安)I. Cracking Password(序列检验,BSGS,细节题)
整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 2019 ICPC全国邀请赛(西安)I. Cracking Password Weblink http ...
- 2019 ACM - ICPC 上海网络赛 E. Counting Sequences II (指数型生成函数)
繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...
- 2023年ICPC全国邀请赛(陕西)-Volunteer角度
2023年ICPC全国邀请赛(陕西)今日开赛.笔者作为只会调试百行出头的js小游戏的弱鸡学生,只能通过担任志愿者来为赛事贡献一份力量了. (图为开幕式现场) 现场的气氛是很好的,热闹是一定的.作为服务 ...
- 2021 ICPC全国邀请赛(西安)太原理工大学收获3枚奖牌
2021 ICPC 国际大学生程序设计竞赛全国邀请赛,于2021年6月5-6日在西安西北工业大学举行. 这次比赛,太原理工大学共派出3个队伍参加比赛,获得2枚银牌1枚铜牌. 通过这个比赛,锻炼了队伍, ...
- 2019年安徽大学ACM/ICPC实验室新生赛题解
本文仅作个人收藏学习使用 题目及解析来源牛客竞赛网 //作者:王清楚 //链接:https://ac.nowcoder.com/discuss/351408?type=101&order=0& ...
- 2019 ACM/ICPC 南昌站 G,拉格朗日插值
题意: 求∑i=1t∑k=xyf(i,k)\sum^t_{i=1}\sum^y_{k=x}f(i,k)i=1∑tk=x∑yf(i,k) 其中f(i,k)f(i,k)f(i,k)表示1,2,3,.. ...
最新文章
- Cpp 对象模型探索 / 不能被继承的类
- 【渝粤教育】国家开放大学2018年秋季 1166t汉语通论 参考试题
- Java设计模式笔记(8)装饰模式
- 【Python】range和xrange区别
- Git与GitHub学习笔记(一)如何删除github里面的文件夹?
- js排序算法详解-计数排序
- html链接抓取,【SEO工具】网页超链接提取工具(无语网站链接抓取器)
- 计算机网络——数据包抓取与分析
- 利用python爬取飞猪信息_飞猪爬虫项目
- 动态DLL文件的编写和使用(速成)
- 在领导面前吃不开的4种员工,中一条就别指望提拔了,说的真准
- python豆瓣mysql_python爬虫获取豆瓣电影——Python操作MySQL存储数据
- 计算机由哪几种显卡,各类显卡大比拼,你会选择哪一款显卡使用?
- 搜狐 Hive SQL 血缘关系解析与应用
- anaconda安装及配置
- DBSCAN原理及matlab仿真代码
- SQL Server使用快捷键查看指定表的信息(字段、备注、索引、约束信息等)
- 关闭安卓手机的按键背景灯
- 基于eNSP的小型企业网(附ensp源文件)
- ie9 error 拒绝访问