解题报告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(i1)/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年第十二届东北四省赛

2016东北四省赛

第13届东北四省赛补题

2014年东北四省赛总结

2019 东北四省赛 A. Apple Business

13th东北四省赛D.Master of Data Structure——暴力+虚树