【解题报告】2021CCPC东北四省赛

【解题报告】2021CCPC东北四省赛

重现赛链接
第一次打了正式的比赛(虽然是线上)摸了个铜,感觉还行但还是失误很多。
签到题开局和学长一起读错题目(英语水平大雾)十多分钟才出了第一题。
还好后面A的题目全都是1发,保了个铜尾。

题目

A-Matrix

思路
【解题报告】2021CCPC东北四省赛_第1张图片

代码
暴力打表代码

#include
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入门题:没有上司的舞会
【解题报告】2021CCPC东北四省赛_第2张图片

代码

#include
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(待补)

思路
线段树还没学区间修改的,待补。可以先瞅瞅学长的代码
【解题报告】2021CCPC东北四省赛_第3张图片

代码

在这里插入代码片

E-Easy Math Problem

思路
数论构造 6 p = p + 2 p + 3 p 6p=p+2p+3p 6p=p+2p+3p
代码

#include 
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
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
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]]=size[fa]size[fb]
嗯!思路清晰的一批,然后我写烂了。find函数忘记递归完存f[x],造成T,比赛结束也没查出来。当场谢罪呜呜呜。

顺便,有人说HDU上数组越界也可能爆TLE
代码

#include
using namespace std;
typedef long long LL;
int T,n,m,Q;
const int N=2e6+10;
struct G{
     
	int u,v,k;
}g[N];
struct query{
     
	int id,p;
}q[N];
LL C[N],ans[N],siz[N],f[N];
bool cmp(G A,G B){
     
	return A.k>B.k;
}
bool cmp2(query A,query B){
     
	return A.p>B.p;
}
void init(){
     
	for(LL i=1;i<=N;i++)C[i]=i*(i-1)/2;//(不开longlong会爆)
}
int find(int x)
{
     
    if(f[x]!=x)f[x]=find(f[x]);
    return f[x];
}
inline LL read(){
     
	LL x=0,y=1;char c=getchar();
	while(c<'0'||c>'9'){
     if(c=='-')y=-1;c=getchar();}
	while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar();
	return x*y;
}
int main(){
     
	init();
	while(~scanf("%d",&T)){
     
		while(T--){
     
			scanf("%d%d%d",&n,&m,&Q);
			for(int i=1;i<=n;i++){
     
				f[i]=i;
				siz[i]=1;
			}
			for(int i=1;i<=m;i++){
     
				g[i].u=read(),g[i].v=read(),g[i].k=read();
			}
			
			sort(g+1,g+1+m,cmp);
			for(int i=1;i<=Q;i++){
     
				q[i].p=read();
				q[i].id=i;
			}
			sort(q+1,q+1+Q,cmp2);
			int pos=1;
			LL sum=0;
			for(int i=1;i<=Q;i++){
     
				while(pos<=m&&g[pos].k>=q[i].p){
     
					if(pos>m)break;
					int fa=find(g[pos].u);
					int fb=find(g[pos].v);
					if(fa!=fb){
     
						sum+=C[siz[fa]+siz[fb]]-C[siz[fa]]-C[siz[fb]];//这里这个式子可以简化成siz[fa]*siz[fb]
						f[fb]=fa;
						siz[fa]+=siz[fb];	
					}
					pos++;
				}
				ans[q[i].id]=sum;
			}
			for(int i=1;i<=Q;i++)printf("%lld\n",ans[i]);
			
		}
	}
	return 0;
}

M-Master of Shuangpin

思路
模拟,读题,打表!
代码

# include 
using namespace std;

map<string, string> mp;

bool func(string str) {
     
    mp["iu"] = "q";
    mp["ei"] = "w";
    mp["uan"] = "r";
    mp["ue"] = "t";
    mp["un"] = "y";
    mp["sh"] = "u";
    mp["ch"] = "i";
    mp["uo"] = "o";
    mp["ie"] = "p";
    mp["ong"] = "s";
    mp["iong"] = "s";
    mp["ai"] = "d";
    mp["en"] = "f";
    mp["eng"] = "g";
    mp["ang"] = "h";
    mp["an"] = "j";
    mp["uai"] = "k";
    mp["ing"] = "k";
    mp["uang"] = "l";
    mp["iang"] = "l";
    mp["ou"] = "z";
    mp["ia"] = "x";
    mp["ua"] = "x";
    mp["ao"] = "c";
    mp["zh"] = "v";
    mp["ui"] = "v";
    mp["in"] = "b";
    mp["iao"] = "n";
    mp["ian"] = "m";
    
    if (mp[str] != "") {
     
        return true;
    } 
    if (mp[str] == "") {
     
        return false;
    }
}

string judge(string str) {
     
    
    if (str.length() == 1) {
     
            cout << str << str ;
    } else if (str == "ang") {
     
        cout << "ah";
    } else if (str == "an") {
     
        cout << "an";
    } else if (str == "ai") {
     
        cout << "ai";
    } else if (str == "en") {
     
        cout << "en";
    } else if (str == "ao") {
     
        cout << "ao";
    }
    
    else {
     
        string substr = str.substr(0, 2);
    if (func(substr)) {
     
        if (func(str.substr(2))) {
     
            cout << mp[substr] << mp[str.substr(2)] ;
        }
        else
        cout << mp[substr] << str.substr(2) ;
    }
    else
    {
     
        if (func(str.substr(1))) {
     
            cout << str[0] << mp[str.substr(1)] ;
        }
        else 
        cout << str[0] << str.substr(1) ;
    }
    }
    
    return "";
}

int main() {
     
    string str;
    char s[6000];
    while (gets(s)) {
     
        for (int i = 0; s[i];i++){
     
        if (s[i] != ' ') {
     
            str += s[i];    
        } else {
     
            judge(str);
            cout << " ";
            str = "";
        }
    }
    judge(str);
    str="";
    s[0]=0;
    cout << endl;
    }
    return 0;
}

你可能感兴趣的:(比赛)