2022.9.7 第一次vp
场次
https://codeforces.com/gym/102966
部分题解
B
题意:给你 \(n (n <= 10^3)\) 个点,求这些点最多构成多少不退化的三角形
思路是首先找到最多点同时在的一条直线(\(mx\) 是直线上最多的点的数量)
容易发现当 \(2 * n >= 3 * mx\) ,答案是\(n / 3\);否则是 \(min(mx / 2, n - mx)\) 。
点击查看代码
// #pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pb push_back
using namespace std;
const int N = 1005;
int t, n, m;
vector<pii> a;
inline ll cross(pii a, pii b) { //叉积
return (1ll * a.first * b.second - 1ll * b.first * a.second);
}
inline int xiangxian(pii a) {
if(a.first > 0 && a.second >= 0) return 0;
else if(a.first <= 0 && a.second > 0) return 1;
else if(a.first < 0 && a.second <= 0) return 2;
else if(a.first >= 0 && a.second < 0) return 3;
}
inline bool cmp(pii b, pii c) {
int fb = xiangxian(b);
int fc = xiangxian(c);
if(fb == fc) {
if(fb == 0) return cross(b, c) > 0;
if(fb == 1) return cross(b, c) < 0;
if(fb == 2) return cross(b, c) < 0;
if(fb == 3) return cross(b, c) > 0;
}
else
return xiangxian(b) < xiangxian(c);
}
int main(){
scanf("%d", &n);
for(int j = 1, x, y; j <= n; j++) {
scanf("%d%d", &x, &y);
a.push_back({x, y});
}
if(n < 3) {
puts("0");
system("pause");
return 0;
}
int mx = 0;
vector<pii> b(n + 5);
for(int cur = 0; cur < n; cur++) {
for(int i = 0, j = 0; i < n; i++) {
if(i != cur) b[j++] = {a[i].first - a[cur].first, a[i].second - a[cur].second};
}
sort(b.begin(), b.begin() + n - 1, cmp);
int cnt = 1;
for(int i = 1; i < n - 1; i++) {
if(cross(b[i], b[i - 1]) == 0) {
cnt++;
}
else {
mx = max(mx, cnt + 1);
cnt = 1;
}
}
mx = max(mx, cnt + 1);
}
if(2 * n >= mx * 3) printf("%d\n", n / 3);
else printf("%d\n", min(mx / 2, n - mx));
system("pause");
return 0;
}
C
C. CLETS Patrols
读完题意然后发现就是矩阵快速幂。
原始矩阵 \(init\) 求 \(m\) 次幂,然后 \(init[1][i]\) 就表示 \(1\) 到 \(i\) 的概率
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 206;
int a,b,n, m;
struct Matrix{
double m[maxn][maxn];
};
Matrix mul(Matrix a,Matrix b, int N){
Matrix c;
for(int i=0;i<N;i++){ //NxN�ľ���
for(int j=0;j<N;j++){
c.m[i][j]=0;
}
}
for(int i=0;i<N;i++){
for(int j=0;j<N;j++){
for(int k=0;k<N;k++){
c.m[i][j] += a.m[i][k]*b.m[k][j];
}
}
}
return c;
}
Matrix ksm(Matrix a,int t, int N){ //t����Ҫ��longlong
Matrix ans;
for(int i=0;i<N;i++){ //NxN�ľ���
for(int j=0;j<N;j++){
if(i==j) ans.m[i][j]=1;
else ans.m[i][j]=0;
}
}
while(t){
if(t&1){
ans=mul(ans,a, N);
}
a=mul(a,a, N);
t/=2;
}
return ans;
}
int main(){
// while(cin>>a>>b>>n){
Matrix init;
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
scanf("%lf", &init.m[i][j]);
}
}
Matrix ans=ksm(init, m, n);
for(int i = 0; i < n; i++) {
printf("%.10f\n", ans.m[0][i]);
}
// }
return 0;
}
D
D. Determine the Winner Marshaland
打表可发现,\(2^{p_i} \mod p_i == 2\)
因此只需要对 $ k + 2$ 进行质因数分解
点击查看代码
// #pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pb push_back
using namespace std;
const int N = 1e6 + 10;
int t, n, m;
int a[N];
int p[N], cnt = 0;
bool isp[N];
void init(int N) {
for (int i = 2; i <= N; ++i) {
if (!isp[i]) p[++cnt] = i;
for (int j = 1; j <= cnt && p[j] * i <= N; ++j) {
isp[i * p[j]] = 1;
if (i % p[j] == 0) break;
}
}
}
int main(){
init(1000);
cin >> t;
while(t--) {
cin >> n;
n += 2;
vector<int> ans;
for(int i = 1; i <= cnt; i++) {
if(1ll * p[i] * p[i] > n) break;
if(n % p[i] == 0) {
if(p[i] > 2) ans.push_back(p[i]);
while(n % p[i] == 0) n /= p[i];
}
}
if(n > 1) ans.push_back(n);
if(ans.empty()) {
puts("-1");
continue;
}
for(auto i : ans) {
printf("%d", i);
if(i == ans.back()) puts("");
else printf(" ");
}
}
system("pause");
return 0;
}
E
E. Enterprise Recognition Program
给定一些点的父子关系,然后有两种操作:单点加和链加(从当前点加到根),两种询问:单点答案和子树答案
由于是先操作完了再询问最终结果,因此可以利用树上差分,每次操作时标记一下,最后做dfs即可 \(O(n)\) 求出最后答案
点击查看代码
// #pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define pii pair<int,int>
#define pb push_back
using namespace std;
const int N = 1e6 + 10;
int t, n, m, q;
int root;
vector<int> e[N];
ll d[N]; //d: single
ll tot[N]; // tot: all
ll v[N];
// 1.建树
// 2.首先处理 op , 树上差分 , dfs求出总的(同时编号(便于之后lb
// 3.print op1:single op2:subtree
void dfs(int now, int fa) { //求single
for(auto i : e[now]) {
if(i == fa) continue;
dfs(i, now);
d[now] += d[i];
}
}
void dfs2(int now, int fa) { //求tot
for(auto i : e[now]) {
if(i == fa) continue;
dfs2(i, now);
tot[now] += tot[i];
}
}
int main(){
scanf("%d%d%d", &n, &m, &q);
for(int i = 1, x; i <= n; i++) {
scanf("%d", &x);
if(!x) {
root = i;
}
else {
e[x].push_back(i);
}
}
for(int i = 1, op, pos, v; i <= m; i++) {
scanf("%d%d%d", &op, &pos, &v);
if(op == 2) { //链加
d[pos] += v;
}
else { //单点加
tot[pos] += v;
}
}
dfs(root, root);
for(int i = 1; i <= n; i++) {
tot[i] += d[i];
v[i] = tot[i];
}
dfs2(root, root);
for(int i = 1, op, pos; i <= q; i++) {
scanf("%d%d", &op, &pos);
if(op == 1) printf("%lld\n", v[pos]);
else printf("%lld\n", tot[pos]);
}
system("pause");
return 0;
}
总结
这场大部分都是数学题,我们一共AC了9题
其中我过了 \(L\) 、 \(C\)
比赛体验总体挺好的,就是后期卡在了 \(B\) 和 \(J\)

浙公网安备 33010602011771号