解题报告2021CCPC东北四省赛
Posted 鱼竿钓鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解题报告2021CCPC东北四省赛相关的知识,希望对你有一定的参考价值。
【解题报告】2021CCPC东北四省赛
重现赛链接
第一次打了正式的比赛(虽然是线上)摸了个铜,感觉还行但还是失误很多。
签到题开局和学长一起读错题目(英语水平大雾)十多分钟才出了第一题。
还好后面A的题目全都是1发,保了个铜尾。
题目
A-Matrix
思路
代码
暴力打表代码
#include<iostream>
using namespace std;
typedef long long LL;
const int N=5005,mod=998244353;
LL fac[N*N]={1,1};//0!是1啊!
LL qmi(LL a, LL k, LL p) // 快速幂模板
{
int res = 1 % p;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
LL C(LL a, LL b, LL p) // 通过定理求组合数C(a, b)
{
if (a < b) return 0;
LL x = 1, y = 1; // x是分子,y是分母
for (int i = a, j = 1; j <= b; i --, j ++ )
{
x = (LL)x * i % p;
y = (LL) y * j % p;
}
return x * (LL)qmi(y, p - 2, p) % p;
}
LL lucas(LL a, LL b, LL p)
{
if (a < p && b < p) return C(a, b, p);
return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
int main(){
freopen ( "db.out" , "w" , stdout ) ;
for(int i=2;i<=N*N;i++)fac[i]=fac[i-1]*i%mod;
for(LL k=1;k<=5000;k++){
LL n=k;
LL ans=0;
for(LL i=1;i<=n;i++)ans=(ans+lucas(n*n-i,n-1,mod)*n%mod*fac[n]%mod*fac[n*n-n]%mod)%mod;
cout<<ans%mod<<",";
}
fclose ( stdout ) ;
}
C-Vertex Deletion
思路
树形DP没写过,以前只写过一道依赖背包有点类似树形DP。
既然没学过那就学吧!
树形DP入门题:没有上司的舞会
代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10,mod=998244353;
typedef long long LL;
int n;
vector<int>v[N];
LL f[N][3];
void dfs(int u,int fa){
f[u][0]=f[u][1]=f[u][2]=1;
for(int j:v[u]){
if(j==fa)continue;
dfs(j,u);
//递归完后开始更新子树,然后一层层向上更新
f[u][0]=f[u][0]*(f[j][0]+f[j][1])%mod;
f[u][1]=f[u][1]*(f[j][0]+f[j][1]+f[j][2])%mod;
f[u][2]=f[u][2]*f[j][0]%mod;
}
f[u][1]-=f[u][2];
if(f[u][1]<0)f[u][1]+=mod;
}
int main(){
int T;
while(~scanf("%d",&T)){
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++)v[i].clear();
for(int i=0,a,b;i<n-1;i++){
scanf("%d%d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1,-1);
printf("%lld\\n",(f[1][0]+f[1][1])%mod);
}
}
return 0;
}
D- Lowbit(待补)
思路
线段树还没学区间修改的,待补。可以先瞅瞅学长的代码
代码
在这里插入代码片
E-Easy Math Problem
思路
数论构造
6
p
=
p
+
2
p
+
3
p
6p=p+2p+3p
6p=p+2p+3p
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5;
int t;
int main() {
int T;
long long n;
long long cnt;
cin >> t;
while(t--)
{
cin>>n;
cnt=6*n;
cout<<cnt<<" "<<3<<endl;
cout<<cnt/6<<" "<<cnt/3<<" "<<cnt/2<<endl;
}
}
I-Takeaway
思路
C语言模拟题,但是开局三人蜜汁凌乱读错题目
代码
#include<bits/stdc++.h>
using namespace std;
const int N=15;
int a[20]={7, 27, 41, 49, 63, 78, 108};
int main(){
int T;
scanf("%d",&T);
while(T--){
int n;scanf("%d",&n);
int sum = 0, each;
for (int i = 0; i < n; i++) {
scanf("%d", &each);
sum += a[each-1];
}
if (sum >= 120) {
printf("%d\\n", sum -50);
} else if (sum >= 89) {
printf("%d\\n", sum - 30);
} else if (sum >= 69) {
printf("%d\\n", sum - 15);
} else {
printf("%d\\n", sum);
}
}
return 0;
}
J-Transform
思路
几何题目
罗德里格旋转公式
需要注意的是是绕单位向量,所以要转换一下
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5007, M = 50007, INF = 0x3f3f3f3f;
const double DINF = 1e18, eps = 1e-8, Pi=acos(-1.0);
inline double R_to_D(double rad)//弧度转角度
{ return 180/Pi*rad; }
inline double D_to_R(double D)//角度转弧度
{ return Pi/180*D; }
struct Point{
double x, y, z;
Point(double x = 0, double y = 0, double z = 0):x(x), y(y), z(z){ }//构造函数
};
//!注意区分点和向量
typedef Point Vector;
//向量平移之后还是那个向量,所以只需要原点和向量的终点即可
//!向量 + 向量 = 向量,点 + 向量 = 向量
Vector operator + (Vector A, Vector B){return Vector(A.x + B.x, A.y + B.y, A.z+B.z);}
//!点 - 点 = 向量(向量BC = C - B)
Vector operator - (Point A, Point B){return Vector(A.x - B.x, A.y - B.y, A.z-B.z);}
//!向量 * 数 = 向量
Vector operator * (Vector A, double p){return Vector(A.x * p, A.y * p, A.z * p);}
//!向量 / 数 = 向量
Vector operator / (Vector A, double p){return Vector(A.x / p, A.y / p, A.z / p);}
//!点/向量的比较函数
bool operator < (const Point& a, const Point& b) {
if(a.x!=b.x)return a.x<b.x;
else if(a.y!=b.y)return a.y<b.y;
else return a.z<b.z;
}
//!点积(满足交换律)
double Dot(Vector A, Vector B){return A.x * B.x + A.y * B.y + A.z * B.z;}
//叉乘
Vector multi(Vector A,Vector B){return Vector(A.y*B.z-B.y*A.z,B.x*A.z-A.x*B.z,A.x*B.y-B.x*A.y);}
//转单位向量
Vector To_UnitVector(Vector U){
double k=sqrt(Dot(U,U));
return Vector(U/k);
}
//罗德里格斯公式
Vector eval(Vector U,Vector V,double r){
return V*cos(r)+U*Dot(U,V)*(1-cos(r))+multi(U,V)*sin(r);
}
int main(){
int T;
while(~scanf("%d",&T)){
while(T--){
double A,B,C,x,y,z,r;
Vector U,V,P,Q;
scanf("%lf %lf %lf %lf %lf %lf %lf",&A,&B,&C,&x,&y,&z,&r);
U={A,B,C};V={x,y,z};
U=To_UnitVector(U);
P=eval(U,V,D_to_R(r));
Q=eval(U,V,D_to_R(-r));
if(P.z>Q.z)printf("%.8lf %.8lf %.8lf\\n",P.x,P.y,P.z);
else printf("%.8lf %.8lf %.8lf\\n",Q.x,Q.y,Q.z);
}
}
}
K-CITY
思路
第一次看以为是什么图论题目先放了,后面仔细瞅瞅发现和连通性有关,果断并查集维护连通块大小。然后对查询排序后离线查询,然后再用类似最小生成树的方式慢慢增加路径。
每次合并的贡献是:
C
[
i
]
=
i
∗
(
i
−
1
)
/
2
C[i]=i*(i-1)/2
C[i]=i∗(i−1)/2
C
[
s
i
z
e
[
f
a
]
+
s
i
z
e
[
f
b
]
]
−
C
[
s
i
z
e
[
f
a
]
]
−
C
[
s
i
z
e
[
f
b
]
]
=
s
i
z
e
[
f
a
]
∗
s
i
z
e
[
f
b
]
C[size[fa]+size[fb]]-C[size[fa]]-C[size[fb]]=size[fa]*size[fb]
C[size[fa]+size[fb]]−C[size[fa]]−C[size[fb]]=18年第十二届东北四省赛