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 意义下是等比数列,也就意味着有两种情况:

  1. 本身就是 ak,ak+1,ak+2⋯a^k,a^{k+1},a^{k+2}\cdotsak,ak+1,ak+2⋯ 的等比数列,有没有模数均可。

  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−1​bi+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 2​modp=bi−1​bi+1​modpbi 2​≡bi−1​bi+1​modpbi 2​−bi−1​bi+1​≡0modp​

显然有 p∣bi2−bi−1bi+1p\ | \ b_i^{\ 2}-b_{i-1}b_{i+1}p ∣ bi 2​−bi−1​bi+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−1​bi+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−1​bi+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+1​modp=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−1​bi+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−1​bi+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−1​bi+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)相关推荐

  1. 2019 ACM - ICPC 全国邀请赛(南昌) 题解(9 / 12)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 目录 The 2019 ICPC China Nanchang National Invitation ...

  2. 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 ...

  3. 2019 ACM - ICPC 西安邀请赛 B. Product (杜教筛) 简单数论(bushi)

    G.(2019 ACM/ICPC 全国邀请赛(西安)B) Product Weblink https://nanti.jisuanke.com/t/39269 Problem && S ...

  4. 2019 ICPC全国邀请赛(西安)I. Cracking Password(序列检验,BSGS,细节题)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 2019 ICPC全国邀请赛(西安)I. Cracking Password Weblink http ...

  5. 2019 ACM - ICPC 上海网络赛 E. Counting Sequences II (指数型生成函数)

    繁凡出品的全新系列:解题报告系列 -- 超高质量算法题单,配套我写的超高质量题解和代码,题目难度不一定按照题号排序,我会在每道题后面加上题目难度指数(1∼51 \sim 51∼5),以模板题难度 11 ...

  6. 2023年ICPC全国邀请赛(陕西)-Volunteer角度

    2023年ICPC全国邀请赛(陕西)今日开赛.笔者作为只会调试百行出头的js小游戏的弱鸡学生,只能通过担任志愿者来为赛事贡献一份力量了. (图为开幕式现场) 现场的气氛是很好的,热闹是一定的.作为服务 ...

  7. 2021 ICPC全国邀请赛(西安)太原理工大学收获3枚奖牌

    2021 ICPC 国际大学生程序设计竞赛全国邀请赛,于2021年6月5-6日在西安西北工业大学举行. 这次比赛,太原理工大学共派出3个队伍参加比赛,获得2枚银牌1枚铜牌. 通过这个比赛,锻炼了队伍, ...

  8. 2019年安徽大学ACM/ICPC实验室新生赛题解

    本文仅作个人收藏学习使用 题目及解析来源牛客竞赛网 //作者:王清楚 //链接:https://ac.nowcoder.com/discuss/351408?type=101&order=0& ...

  9. 2019 ACM/ICPC 南昌站 G,拉格朗日插值

    题意: 求∑i=1t∑k=xyf(i,k)\sum^t_{i=1}\sum^y_{k=x}f(i,k)i=1∑t​k=x∑y​f(i,k) 其中f(i,k)f(i,k)f(i,k)表示1,2,3,.. ...

最新文章

  1. Cpp 对象模型探索 / 不能被继承的类
  2. 【渝粤教育】国家开放大学2018年秋季 1166t汉语通论 参考试题
  3. Java设计模式笔记(8)装饰模式
  4. 【Python】range和xrange区别
  5. Git与GitHub学习笔记(一)如何删除github里面的文件夹?
  6. js排序算法详解-计数排序
  7. html链接抓取,【SEO工具】网页超链接提取工具(无语网站链接抓取器)
  8. 计算机网络——数据包抓取与分析
  9. 利用python爬取飞猪信息_飞猪爬虫项目
  10. 动态DLL文件的编写和使用(速成)
  11. 在领导面前吃不开的4种员工,中一条就别指望提拔了,说的真准
  12. python豆瓣mysql_python爬虫获取豆瓣电影——Python操作MySQL存储数据
  13. 计算机由哪几种显卡,各类显卡大比拼,你会选择哪一款显卡使用?
  14. 搜狐 Hive SQL 血缘关系解析与应用
  15. anaconda安装及配置
  16. DBSCAN原理及matlab仿真代码
  17. SQL Server使用快捷键查看指定表的信息(字段、备注、索引、约束信息等)
  18. 关闭安卓手机的按键背景灯
  19. 基于eNSP的小型企业网(附ensp源文件)
  20. ie9 error 拒绝访问

热门文章

  1. 笔试题——max pooling滑动窗口实现(python 代码)
  2. CSS中怎么让DIV居中
  3. HTML5 - Websocket
  4. python新手任务:python循环嵌套
  5. 30天提升技术人的写作力-第二天
  6. SFB 项目经验-65-使用域管理员安装不了Exchange 2010 SP3 CU21
  7. 堆、栈、方法区、静态代码块---Java
  8. 面对不同用户,数据中心如何将服务做到极致
  9. MySQL数据库-错误1166 - Incorrect column name 'xxx' 的解决方法
  10. Label的作用是什么?是怎么用的?