2023杭电多校(5)
1001
直接求点到线段最小距离即可
开始还以为要有啥优化,但是hdu的机子能跑1e8诶(
#include <iostream> #include <cmath> #include <bits/stdc++.h> using namespace std; #define eps 1e-10 /********** 定义点 **********/ struct Point{ double x,y; Point(double x=0,double y=0):x(x),y(y) {} }; /********** 定义向量 **********/ typedef Point Vector; /********** 向量 + 向量 = 向量 **********/ Vector operator + (Vector a,Vector b) { return Vector(a.x+b.x,a.y+b.y); } /********** 点 - 点 = 向量 **********/ Vector operator - (Point a,Point b) { return Vector(a.x-b.x,a.y-b.y); } /********** 向量 * 数 = 向量 **********/ Vector operator * (Vector a,double b) { return Vector(a.x*b,a.y*b); } /********** 向量 / 数 = 向量 **********/ Vector operator / (Vector a,double b) { return Vector(a.x/b,a.y/b); } bool operator < (const Point& a,const Point& b) { return a.x<b.x || (a.x==b.x && a.y<b.y); } int dcmp(double x) //减少精度问题 { if(fabs(x)<eps) return 0; else return x<0?-1:1; } bool operator == (const Point &a,const Point &b) //判断两点是否相等 { return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0; } /********** 向量点积 **********/ double Dot(Vector a,Vector b) { return a.x*b.x+a.y*b.y; } /********** 向量长度 **********/ double Length(Vector A) { return sqrt(Dot(A,A)); } /********** 两向量角度 *********/ double Angle(Vector A,Vector B) { return acos(Dot(A,B)/Length(A)/Length(B)); } /********** 2向量求叉积 **********/ double Cross(Vector a,Vector b) { return a.x*b.y-b.x*a.y; } /********** 3点求叉积 **********/ double Cross(Point a,Point b,Point c) { return (c.x-a.x)*(b.y-a.y) - (c.y-a.y)*(b.x-a.x); } /********** 向量旋转 ***********/ Vector Rotate(Vector A,double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad)); } /********** 向量的单位法线 *********/ Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y/L,A.x/L); } /********** 点和直线 **********/ /********** 求两点间距离 **********/ double dist(Point a,Point b) { return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) ); } /********** 直线交点 **********/ Point GetLineIntersection(Point P,Vector v,Point Q,Vector w) { Vector u = P-Q; double t = Cross(w,u) / Cross(v,w); return P+v*t; } /********** 点到直线的距离 ***********/ double DistanceToLine(Point P,Point A,Point B) { Vector v1 = B-A,v2 = P-A; return fabs(Cross(v1,v2)) / Length(v1); //如果不取绝对值,得到的是有向距离 } /********** 点到线段的距离 **********/ double DistanceToSegment(Point P,Point A,Point B) { if(A==B) return Length(P-A); Vector v1 = B-A,v2 = P-A,v3 = P-B; if(dcmp(Dot(v1,v2))<0) return Length(v2); else if(dcmp(Dot(v1,v3)) > 0) return Length(v3); else return fabs(Cross(v1,v2)) / Length(v1); } Point p1[10005],p2[10005]; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int N,M; cin >> N >> M; for (int i = 1 ; i <= N ; i ++) cin >> p1[i].x >> p1[i].y; for (int i = 1 ; i <= M ; i ++) cin >> p2[i].x >> p2[i].y; for (int i = 1 ; i <= M ; i ++){ double ans = 1e9+7; for (int j = 2 ; j <= N ; j ++){ ans = min(ans,DistanceToSegment(p2[i],p1[j],p1[j-1])); } cout << fixed << setprecision(4) << ans << endl; } return 0; }
1003
直接PAM+字符串hash遍历所有回文子串即可
显然,满足题意的子串一定回文,而且它切一半相等。后者哈希判断即可。
#include <bits/stdc++.h> #define ull unsigned long long #define ll long long const ull h1 = 1145142017; const int N = 1e5+10; ull ha[N]; ull pw[N]; using namespace std; ull GetHash(int l, int r) { if (l == 0) return ha[r]; return ha[r] - ha[l - 1] * pw[r - l + 1]; } bool Check(int L,int R){ int Len = R-L+1; if (Len & 1) return false; int mid = (L+R)>>1; //cout << L << " " << R << " " << Len << " " << GetHash(L,mid)<< endl; return (GetHash(L,mid) == GetHash(mid+1,R)); } ll Ans = 0; struct Palindromic_Tree { int nxt[N][30], fail[N], cnt[N]; int num[N], len[N], s[N], id[N]; int last, n, p; int newnode(int l) { memset(nxt[p], 0, sizeof(nxt[p])); cnt[p] = num[p] = 0; len[p] = l; return p++; } void init() { p = 0; newnode(0), newnode(-1); last = n = 0; s[0] = -1; fail[0] = 1; } int get_fail(int x) { while (s[n - len[x] - 1] != s[n]) x = fail[x]; return x; } void add(int c) { c -= 'a'; s[++n] = c; int cur = get_fail(last); if (!nxt[cur][c]) { int now = newnode(len[cur] + 2); fail[now] = nxt[get_fail(fail[cur])][c]; nxt[cur][c] = now; num[now] = num[fail[now]] + 1; } last = nxt[cur][c]; cnt[last]++, id[last] = n; } ll Count() { for (int i = p - 1; i >= 0; i--) cnt[fail[i]] += cnt[i]; for (int i = 2; i < p; i++) { if (Check(id[i] - len[i], id[i] - 1)) { Ans += cnt[i]; } } return 0; } } pam; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); pw[0] = 1; for (int i = 1 ; i <= N ; i ++) pw[i] = pw[i-1] * h1; int T; cin >> T; while(T--){ Ans = 0; string ss; cin >> ss; pam.init(); int Len = ss.length(); for (int i = 0 ; i < Len ; i ++) pam.add(ss[i]); ha[0] = ss[0]; for (int i = 1; i < Len; i++) { ha[i] = ha[i - 1] * h1 + ss[i]; } pam.Count(); cout << Ans << endl; } }
1005
考虑一个比较经典的问题:
把$n$分成$m$个数的和,然后每个数字最大不超过$k$
那这个东西如果不考虑后面说的,显然直接隔板
那考虑到后面说的就容斥一下就好啦。用$(-1)^k$那个容斥
然后$*n!$把所有的数字放进我们的求和里,再$*\frac{1}{m!}$处理一下组的顺序问题就好
实际上赛场上并没有非常想清楚$\frac{1}{m!}$,想着反正肯定$n!$得乘上去,然后对比了一下样例发现差个$m!$,交了一发发现过了(
#include <bits/stdc++.h> using namespace std; #define int long long const int maxn = 1e6+10; const int mod = 998244353; int n,m,k,fac[maxn],inv[maxn]; int quick(int x,int n) { int ans = 1; for( ; n ; n>>=1,x=x*x%mod ) if( n&1 ) ans = ans*x%mod; return ans; } int C(int n,int m) { if( m>n ) return 0; return fac[n]*inv[m]%mod*inv[n-m]%mod; } signed main() { ios::sync_with_stdio( false ); cin.tie( 0 ); cout.tie( 0 ); fac[0] = 1; inv[0] = 1; for(int i=1;i<=1000000;i++) fac[i] = fac[i-1]*i%mod, inv[i] = quick( fac[i],mod-2 ); int t; cin >> t; while( t-- ) { cin >> k >> m >> n; int ans = C(k-1,m-1); for(int i=1; ;i++) { if( k-1-n*i<0 ) break; if( i&1 ) ans = ( ans-C(m,i)*C(k-1-n*i,m-1)%mod +mod)%mod; else ans = ( ans+C(m,i)*C(k-1-n*i,m-1)%mod )%mod; } ans = (1ll*ans * fac[k] %mod * inv[m]%mod)%mod; cout << ans << endl; } }
1006
发现颜色数非常少,而且只和两个bag的颜色有关系
于是直接$f[i][j][k]$表示考虑到$i$,1袋颜色为$j$,2袋颜色为$k$的答案即可。
#include <bits/stdc++.h> using namespace std; int T; int dp[100005][5][5]; string ss; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> T; while (T--){ cin >> ss; int Len = ss.length(); for (int i = 0 ; i < Len ; i ++) for (int j = 0 ; j <= 3 ; j ++) for (int k = 0 ; k <= 3 ; k ++) dp[i][j][k] = -1e9; for (int i = 0 ; i < Len ; i ++){ int x; if (ss[i] == 'R') x = 1; else if (ss[i] == 'G') x = 2; else x = 3; dp[i][x][0] = max(dp[i][x][0],dp[i-1][0][0]); dp[i][0][0] = max(dp[i][0][0],dp[i-1][0][0]); if (i == 0) continue; for (int j = 1 ; j <= 3 ; j ++) for (int k = 0 ; k <= 3 ;k ++){ dp[i][j][k] = max(dp[i][j][k],dp[i-1][j][k]); if (k == 0){ dp[i][j][x] = max(dp[i][j][x],dp[i-1][j][k]); continue; } if (x == j && x == k){ for (int l = 1 ; l <= 3 ; l ++) dp[i][l][0] = max(dp[i][l][0],dp[i-1][x][x] + 1); } if (x!=j && x!=k && j!=k){ for (int l = 1 ; l <= 3 ; l ++) for (int m = 1 ; m <= 3 ; m ++){ dp[i][l][m] = max(dp[i][l][m],dp[i-1][j][k]); } } } } int ans = 0; for (int i = 0 ; i <= 3 ; i ++) for (int j = 0 ; j <=3 ; j ++) ans = max(ans,dp[Len-1][i][j]); cout << ans << endl; } }
1007
队友写的签到,并不知道是啥(
但他预处理没做好被卡了3发,令人感慨(
#include <iostream> #include <algorithm> #include <cstring> #include <vector> #include <queue> #define x first #define y second #define pb push_back using namespace std; typedef long long LL; typedef pair<int, int> PII; const int N = 1000010; const int p = 998244353; int n, m, a, b; int fact[N], infact[N]; int qmi(int a, int k) { if (k == 0) return 1; if (k < 0) exit(0); int res = 1; while (k) { if (k & 1) res = (LL)res * a % p; a = 1ll * a * a % p; k >>= 1; } return res; } void init() { fact[0] = 1, infact[0] = 1; for (int i = 1; i < N; i++) { fact[i] = (LL)fact[i - 1] * i % p; infact[i] = (LL)infact[i - 1] * qmi(i, p - 2) % p; } } int pw[N+10],pw1[N+10]; void solve() { cin >> n >> m >> a >> b; int ans = 0; int sum = 0; int w0 = qmi(b, p - 2); int w1 = (LL)a * w0 % p; int w2 = (LL)(b - a) * w0 % p; pw[0] = pw1[0] = 1; for (int i = 1 ; i <= n ; i ++){ pw[i] = 1ll * pw[i-1] * w1%p; pw1[i] = 1ll * pw1[i-1] * w2 %p; } for (int i = 1; i <= n; i++) { LL res = 1; res = (LL)res * fact[n] % p * infact[i] % p * infact[n - i] % p; res = (LL)res * pw[i] % p; res = (LL)res * pw1[n-i] % p; sum = (LL)(sum + qmi(i, m)) % p; ans = (LL)(ans + res * sum % p) % p; } cout << (ans % p + p) % p << endl; return; } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int T = 1; cin >> T; init(); while (T--) { solve(); } return 0; }
1009
发现$dfs$两次即可,模拟一下这个过程
给队友讲了一遍思路扔给他写的(
#include <iostream> #include <algorithm> #include <cstring> #include <vector> #include <queue> #include <set> #include <cmath> #define x first #define y second #define pb push_back using namespace std; typedef long long LL; typedef pair<int, int> PII; const int N = 2000010, M = 4000010; int n, m; int h[N], h1[N], e[M], ne[M], idx; int w[N]; vector<int> v[N]; int cnt; int from[N]; int d[N]; int ans; void add(int h[], int a, int b) { e[idx] = b, ne[idx] = h[a], h[a] = idx++; } void dfs(int u, int fa, int num) { cnt = max(cnt, num); for (int i = h[u]; i != -1; i = ne[i]) { int j = e[i]; if (j == fa) continue; if (w[u] == j) { v[num].pb(j); dfs(j, u, num); } else { // cout << "t2" << endl; ++cnt; v[cnt].pb(j); from[cnt] = num; dfs(j, u, cnt); } } } void dfs2(int u, int fa, int depth) { ans = max(ans, depth); for (int i = h1[u]; i != -1; i = ne[i]) { int j = e[i]; if (j == fa) continue; dfs2(j, u, depth + d[j]); } } void solve() { cin >> n; memset(h, -1, sizeof h); memset(h1, -1, sizeof h1); memset(e, 0, sizeof e); memset(ne, 0, sizeof ne); memset(w, 0, sizeof w); memset(from, 0, sizeof from); memset(d, 0, sizeof d); for (int i = 1; i <= cnt; i++) v[i].clear(); idx = cnt = ans = 0; for (int i = 1; i <= n; i++) { int t; cin >> t; if (t == 0) continue; add(h, i, t), add(h, t, i); } for (int i = 1; i <= n; i++) cin >> w[i]; v[1].pb(1); dfs(1, -1, 1); d[1] = ceil(log(2 * v[1].size()) / log(2)); for (int i = 1; i <= cnt; i++) { d[i] = d[from[i]] + ceil(log(2 * v[i].size()) / log(2)); } int ans = 0; for (int i = 1; i <= cnt; i++) ans = max(ans, d[i]); // for (int i = 1; i <= cnt; i++) // cout << i << " from " << from[i] << endl; // for (int i = 2; i <= cnt; i++) // { // add(h1, i, from[i]), add(h1, from[i], i); // } // dfs2(1, -1, d[1]); cout << ans << endl; // cout << cnt << endl; return; } int main() { int size(512 << 20); // 512M __asm__("movq %0, %%rsp\n" ::"r"((char *)malloc(size) + size)); // YOUR CODE ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); int T = 1; cin >> T; while (T--) { solve(); } exit(0); }
1012
暴力算一下度然后算个组合数即可
#include <bits/stdc++.h> #define int long long using namespace std; const int MOD = 1000000007; const int mx = 1e6; int d[mx+10]; int ans[mx+10]; int fac[mx+10],inv[mx+10]; int C(int n,int r){ return fac[n] * inv[r] % MOD * inv[n-r]%MOD; } int Pow(int x,int y){ int ans = 1; for (;y;y>>=1){ if (y & 1) ans = 1ll *ans * x %MOD; x = 1ll * x * x %MOD; } return ans; } signed main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); fac[0] = 1; int T; cin >> T; for (int i = 1 ; i <= mx ; i ++) fac[i] = 1ll * fac[i-1] * i %MOD; inv[mx] = Pow(fac[mx],MOD-2); for (int i = mx-1 ; i >= 1 ; i --) inv[i] = 1ll*inv[i+1]*(i+1)%MOD; inv[0] = 1; //cout << C(2,2) << endl; while (T--){ int N,M; cin >> N >> M; for (int i = 1 ; i <= N ; i++) d[i] = ans[i] = 0; for (int i =1 ; i <= M ; i ++){ int u,v; cin >> u >> v; d[u] ++; d[v] ++; } for (int i = 1 ; i <= N ; i ++){ for (int j = 2 ; j <= d[i] ; j ++){ (ans[j] += C(d[i],j))%=MOD; } } int ans1 = 0; for (int i = 1 ; i <= N ; i ++) ans1 ^= ans[i]; cout << ans1 << endl; } return 0; }
队友不在,接近单挑,好累哦(
1002想了一下,把那个$gcd(2^i-1,2^j-1)$=$2^{gcd(i,j)}-1$的结论搞了出来
然后发现是个非常经典的莫比乌斯反演+积性函数前缀和题,但是来不及写了(x
干啥啥不行