YC2023:《实战笔记》第二章 顺序结构 题解-基础篇

发布时间 2023-09-01 23:17:23作者: One_JuRuo

不要相信这篇题解的任何一个字,包括标题和这句话。

省流-恶搞题目:A,B,C,M,Q。

题目

A

思路

这道题实在是太难啦,蒟蒻想了半天只能用 ASCLL 码做。

AC code

#include<bits/stdc++.h>
using namespace std;
int main()
{
	char s[13]={72,101,108,108,111,44,87,111,114,108,100,33};
	printf("%s",s);
	return 0;
}

B

思路

实在是太难了,比第一题还要难,没有想到 \(O(1)\) 的做法,只想到了 \(O(\log 5)\) 的线段树。

很容易想到,区间修改 \([1,a]\)\([1,b]\),然后再区间查询,但是发现 \(a,b\) 太大,开不了那么大的线段树。所以换一种思路。

发现只需要区间查询就好,所以还算是比较水的线段树。

AC code

#include<bits/stdc++.h>
using namespace std;
struct node{int l,r,sum,len,tag;}t[20];
int a[20];
inline void pushup(int p){t[p].sum=t[p<<1].sum+t[p<<1|1].sum;}
inline void pushdown(int p)
{
	t[p<<1].sum+=t[p<<1].len*t[p].tag,t[p<<1|1].sum+=t[p<<1|1].len*t[p].tag,t[p<<1].tag+=t[p].tag,t[p<<1|1].tag+=t[p].tag,t[p].tag=0;
}
void build(int p,int l,int r)
{
	t[p].l=l,t[p].r=r,t[p].len=r-l+1;
	if(l==r){t[p].sum=a[l];return;}
	int mid=l+r>>1;
	build(p<<1,l,mid),build(p<<1|1,mid+1,r);
	pushup(p);
}
/*本题不需要的函数*/
void update(int p,int l,int r,int k)
{
	if(t[p].l>=l&&t[p].r<=r){t[p].sum+=t[p].len*k,t[p].tag+=k;return;}
	if(t[p].tag) pushdown(p);
	int mid=t[p].l+t[p].r>>1;
	if(mid>=l) update(p<<1,l,r,k);
	if(mid<r) update(p<<1|1,l,r,k);
	pushup(p);
}
int ask(int p,int l,int r)
{
	if(t[p].l>=l&&t[p].l<=r) return t[p].sum;
	if(t[p].tag) pushdown(p);
	int mid=t[p].l+t[p].r>>1,ans=0;
	if(mid>=l) ans=ask(p<<1,l,r);
	if(mid<r) ans+=ask(p<<1|1,l,r);
	return ans;
}
int main()
{
	scanf("%d%d",&a[1],&a[2]);
	build(1,1,4);
	printf("%d",ask(1,1,4));
	return 0;
}

C

思路

容易发现这道题可以把每一位都看作函数的某一项,然后相乘就是函数多项式相乘,所以很容易地想到 FFT。

AC code

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int N=10000005,M=998244353,G=3,Gi=332748118;
ll a[N],b[N],c[N],ans[N];
int cnt=1,l,r[N];
string s1,s2;
ll fbow(ll a,ll b){
	ll ans=1;
	while(b){
		if(b&1) ans=(ans*a)%M;
		a=(a*a)%M;
		b>>=1;
	}
	return ans;
}
void ntt(ll *A,int t){
	for(ll i=0;i<cnt;i++) if(i<r[i]) swap(A[i],A[r[i]]);
	for(ll mid=1;mid<cnt;mid*=2){
		ll wn;
		if(t==1) wn=fbow(G,(M-1)/(mid*2));
		else wn=fbow(Gi,(M-1)/(mid*2));
		for(ll j=0;j<cnt;j+=(mid*2)){
			ll w=1;
			for(ll k=0;k<mid;k++,w=(w*wn)%M){
				ll x=A[j+k],y=w*A[j+mid+k]%M;
				A[j+k]=(x+y)%M;
				A[j+k+mid]=(x-y+M)%M;
			}
		}
	}
}
int main(){
	cin.tie(0),cin.tie(0); 
	cin>>s1>>s2;
	ll len1=s1.size(),len2=s2.size(),tt=0;
	for(ll i=len1-1;i>=0;i--) a[++tt]=s1[i]-48;
	tt=0;
	for(ll i=len2-1;i>=0;i--) b[++tt]=s2[i]-48; 
	while(cnt<=len1+len2) cnt*=2,l++;
	for(ll i=0;i<cnt;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
	ntt(a,1);ntt(b,1);
	for(ll i=0;i<=cnt;i++) c[i]=(a[i]*b[i])%M;
	ntt(c,-1);
	ll inv=fbow(cnt,M-2);
	for(int i=0;i<=cnt;i++){
		ans[i]+=(ll)(c[i]*inv)%M;
		if(ans[i]>=10){
			ans[i+1]+=ans[i]/10;
			ans[i]%=10;
			cnt+=(i==cnt);
		}
	}
	while(!ans[cnt]&&cnt>=1) cnt--;
    cnt++;
	while(--cnt>=2) cout<<ans[cnt];
	return 0;
}

D

思路

非常的难,蒟蒻想了半天才做出来。

AC code

#include<iostream>
#include<cmath>
using namespace std;
int main()
{
    int h,r;cin>>h>>r;
    const double v=20000/(3.14*r*r*h);
    cout<<ceil(v);
	return 0;
}

E

思路

需要小学奥数,对于本蒟蒻来说实在是太难了。

AC code

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a,b,n;
	cin>>a>>b>>n;
	cout<<(b-a)*(n-1)+a;
	return 0;
}

F

思路

居然是普及组地题目,哇哇哇,对蒟蒻来说太难啦。抠破脑袋才想出来。

AC code

#include<bits/stdc++.h>
using namespace std;
int a,b,c;
int main()
{
	cin>>a>>b>>c;
	cout<<0.2*a+0.3*b+0.5*c;
} 

G

思路

虽然较简单,但是对于蒟蒻而言实在是太难了。

AC code

#include<bits/stdc++.h>
using namespace std;
int a;
int main()
{
	cin>>a>>a;
	cout<<a;
	return 0;
}

H

思路

哇,向零取整,怎么办啊,对蒟蒻来说实在是没天理地难。

AC code

#include<cstdio>
using namespace std;
int main(){
	double a;
	scanf("%lf",&a);
	printf("%d",(int)a);
	return 0;
}

I

思路

怎么上表达式了,难得蒟蒻哇哇叫。

AC code

#include<cstdio>
using namespace std;
int main(){
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	printf("%d",(a+b)*c);
	return 0;
} 

J

思路

太难啦,蒟蒻只能想到用字符串做。

AC code

#include<bits/stdc++.h>
using namespace std;
char s[1145141];
int main()
{
	scanf("%s",s+1);
	for(int i=s.size();i>0;--i) printf("%c",s[i]);
	return 0;
}

K

思路

我测,⚪!

太难啦!!!

AC code

#include<bits/stdc++.h>
using namespace std;
const double pi=3.14159;
double r;
int main()
{
	scanf("%lf",&r);
	printf("%.4lf %.4lf %.4lf",r*2,r*2*pi,r*r*pi);
}

L

思路

怎么回事,还有三次方程,难难难!

AC code

#include<bits/stdc++.h>
using namespace std;
double x,a,b,c,d;
int main()
{
	scanf("%lf%lf%lf%lf%lf",&x,&a,&b,&c,&d);
	printf("%.7lf",a*x*x*x+b*x*x+c*x+d);
}

M

思路

哇,一看就是计算几何,直接上模板,用叉积算面积。

AC code

//计算几何模板:https://www.luogu.com.cn/blog/AuroraWind/ji-suan-ji-he-mu-ban-dian-xiang-liang-xian
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-8,pi=acos(-1.0);
const int N=100005;
inline int dcmp(double x){return (x<-eps)?-1:(x>eps)?1:0;}//判断正负
inline double dabs(double x){return x*dcmp(x);}//绝对值 
/*向量(点)*/
struct vec{double x,y;vec(double _x=0,double _y=0){x=_x;y=_y;}};
inline bool cmp_vec(vec a,vec b){return (a.x!=b.x)?a.x<b.x:a.y<b.y;}
inline double len(vec a){return sqrt(a.x*a.x+a.y*a.y);}//模长 
inline double ang(vec a){return atan2(a.y,a.x);}//角度 
inline vec operator +(const vec &a,const vec &b){return vec(a.x+b.x,a.y+b.y);}
inline vec operator -(const vec &a,const vec &b){return vec(a.x-b.x,a.y-b.y);}
inline vec operator *(const vec &a,const double &b){return vec(a.x*b,a.y*b);}
inline vec operator /(const vec &a,const double &b){return vec(a.x/b,a.y/b);}
inline double operator *(const vec &a,const vec &b){return a.x*b.x+a.y*b.y;}//点积 
inline double operator ^(const vec &a,const vec &b){return a.x*b.y-a.y*b.x;}//叉积
inline vec rot(vec a,double the){return vec(a.x*cos(the)-a.y*sin(the),a.x*sin(the)+a.y*cos(the));}//旋转 
inline vec rot90(vec a){return vec(a.y,-a.x);}//特殊角旋转
inline vec rotpt(vec a,vec b,double the){return b+rot(a-b,the);}//a绕b旋转
/*线*/ 
struct line{vec s,t;line(vec _s=vec(0,0),vec _t=vec(0,0)){s=_s;t=_t;}};//线 
inline double maxx(line l){return max(l.s.x,l.t.x);}//大x
inline double maxy(line l){return max(l.s.y,l.t.y);}//大y 
inline double minx(line l){return min(l.s.x,l.t.x);}//小x
inline double miny(line l){return min(l.s.y,l.t.y);}//小y
inline double ang(line l){return ang(l.t-l.s);}//角度 
inline bool operator <(line &a,line &b){double a1=ang(a.t-a.s),a2=ang(b.t-b.s);return (dcmp(a2-a1))?a2>a1:dcmp((a.t-a.s)^(b.t-b.s))<0;} 
inline bool operator ==(vec &a,vec &b){return (!dcmp(a.x-b.x)&&!dcmp(a.y-b.y));}//点是否相等 
inline double dis(vec a,vec b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}//点距离
inline bool pd_pl(vec a,line b){return !dcmp((a-b.s)^(b.t-b.s));}//点是否在直线上
inline bool pd_px(vec a,line b){return pd_pl(a,b)&&(dcmp((a-b.s)*(a-b.t))<=0);}//点是否在线段上
inline vec footpt(vec a,line b){vec x=a-b.s,y=a-b.t,z=b.t-b.s;double s1=x*z,s2=-1.0*(y*z);return b.s+z*(s1/(s1+s2));}//求垂足(分别求as,at关于st的投影)
inline vec mirror(vec a,line b){return a+(footpt(a,b)-a)*2.0;}//a关于b的对称点
inline double dis_pl(vec a,line b){return dabs((a-b.s)^(a-b.t))/len(b.t-b.s);}//求a到直线b的距离(面积除以底边长)
inline double dis_px(vec a,line b){return (dcmp((a-b.s)*(b.t-b.s))<0)?len(a-b.s):(dcmp((a-b.t)*(b.t-b.s))>0)?len(a-b.t):dis_pl(a,b);}//求a到线段b的距离
inline vec pt_px(vec a,line b){return (dcmp((a-b.s)*(b.t-b.s))<0)?b.s:(dcmp((a-b.t)*(b.t-b.s))>0)?b.t:footpt(a,b);}//在线段b上与a最近的点
inline vec cross(line a,line b){vec x=a.t-a.s,y=b.t-b.s,z=a.s-b.s;return a.s+x*((y^z)/(x^y));}//求a与b的交点
inline bool pd_cross_lx(line a,line b){return (!dcmp((a.t-a.s)^(b.t-b.s)))?0:pd_px(cross(a,b),a);}//线段a与直线b是否相交
inline bool pd_cross_xx(line a,line b){return pd_cross_lx(a,b)&&pd_cross_lx(b,a);}//判断线段a是否与线段b相交
inline bool pd_cross_xx_(line a,line b)//判断两线段是否相交 (另一种方法,是否跨立) 
{
    if(maxx(a)<minx(b)||maxy(a)<miny(b)) return false;
    if(maxx(b)<minx(a)||maxy(b)<miny(a)) return false;
    double s1=(a.t-a.s)^(b.s-a.s),s2=(a.t-a.s)^(b.t-a.s);
    double s3=(b.t-b.s)^(a.s-b.s),s4=(b.t-b.s)^(a.t-b.s);
    return dcmp(s1)*dcmp(s2)<=0&&dcmp(s3)*dcmp(s4)<=0;//a的端点在b的两侧且b的端点在a的两侧 
}
inline double s_t(vec a,vec b,vec c){return dabs((b-a)^(c-a))/2;}//已知三点求三角形面积 
/*多边形*/
struct pol
{
    vector<vec> pt;
    inline vec& operator [](int x){return pt[x];}
    inline int ne(int x){return (x<pt.size()-1)?x+1:0;}
    inline void insert(vec p){pt.push_back(p);}
    inline void clear(){pt.clear();}
    inline int include(vec p)//点在多边形外:0,在多边形内:1,在多边形边上:2 
    {
        int cnt=0;
        for(int i=0;i<pt.size();i++)//射线法判断,射线方向为x轴正方向 
        {
            vec s=pt[i],t=pt[ne(i)];line l=line(s,t);
            if(pd_px(p,l)) return 2;
            if(dcmp(p.y-miny(l))>=0&&dcmp(maxy(l)-p.y)>0)
            if(dcmp(s.x+((p.y-s.y)/(t.y-s.y)*(t.x-s.x))-p.x)>0) cnt++;
        }
        return cnt&1;//偶数个交点则在多边形外,奇数个交点则在多边形内 
    }
    inline double s_p()//多边形面积 
    {
        double ans=0;
        for(int i=1;i<pt.size()-1;i++) ans+=(pt[i]-pt[0])^(pt[ne(i)]-pt[0]);
        return dabs(ans)/2;
    }
    inline double c_p()//多边形周长 
    {
        double ans=0;
        for(int i=0;i<pt.size();i++) ans+=dis(pt[i],pt[ne(i)]);
        return ans;
    }
    inline bool pd_l(vec x,vec l,vec r){return dcmp((l-x)^(r-x))<=0;}//xl是否在xr的左侧
    inline int include_(vec p)//二分法判断点是否在多边形内
    {
        int n=pt.size();
        if(!pd_l(pt[0],p,pt[1])) return 0;
        if(!pd_l(pt[0],pt[n-1],p)) return 0; 
        if(pd_px(p,line(pt[0],pt[1]))) return 2;
        if(pd_px(p,line(pt[0],pt[n-1]))) return 2;
        int l=1,r=n-2,ans=1,mid;
        while(l<=r)//二分找到最接近线(pt[0],p)的(pt[0],pt[ans]) 
        {
            mid=l+r>>1;
            if(!pd_l(pt[0],pt[mid],p)) l=mid+1,ans=mid;
            else r=mid-1;
        }
        if(!pd_l(pt[ans],p,pt[ne(ans)])) return 0;
        if(pd_px(p,line(pt[ans],pt[ne(ans)]))) return 2;
        return 1;
    } 
};
/*凸包*/
inline void andrew(pol &p)
{
    vector<vec>q(p.pt.size()<<1);int top=0,n=p.pt.size();
    sort(p.pt.begin(),p.pt.end(),cmp_vec),q[top]=p[0];
    for(int i=1;i<n;i++)
    {
        while(top&&dcmp((q[top-1]-q[top])^(q[top-1]-p[i]))<=0) top--;
        q[++top]=p[i];
    }
    int tot=top;
    for(int i=n-2;i>=0;i--)
    {
        while(top>tot&&dcmp((q[top-1]-q[top])^(q[top-1]-p[i]))<=0) top--;
        q[++top]=p[i];
    }
    if(n>1) top--;
    p.clear();
    for(int i=0;i<=top;i++) p.insert(q[i]);
}
/*旋转卡壳*/
inline double diam(pol p)
{
    int n=p.pt.size();double ans=0;
    for(int i=0,j=1;i<n;i++)
    {
        for(;;j=p.ne(j)) if(dcmp(s_t(p[j],p[i],p[p.ne(i)])-s_t(p[p.ne(j)],p[i],p[p.ne(i)]))>=0) break;
        ans=max(ans,max(dis(p[j],p[i]),dis(p[j],p[p.ne(i)])));
    }
    return ans;
}
int main()
{
	double x1,x2,x3,y1,y2,y3;
	scanf("%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3);
	printf("%.2lf",s_t(vec(x1,y1),vec(x2,y2),vec(x3,y3)));
}

虽然有很多函数没有用到,但是多打打锻炼码力和熟悉度还是很不错的。(确信

N

思路

略。(编不下去了—)

AC code

#include<bits/stdc++.h>
using namespace std;
int a,b;
int main()
{
	scanf("%d%d",&a,&b);
	printf("%d %d",a/b,a%b);
}

O

思路

哇哇,线段长度,显然也是计算几何,害怕大家审美疲劳,这里放另一个模板。

AC code

//计算几何小板子 
#include<bits/stdc++.h>
using namespace std;
const int eps=1e-8;
const double Pi=acos(-1.0);
int dcmp(double x){return (x<-eps)?-1:(x>eps?1:0);}//小于0返回-1 大于0返回1 等于0返回0
double Abs(double x){return x*dcmp(x);}

//Computer Graphics
namespace CG
{
    struct pt{double x,y;pt(double tx=0,double ty=0){x=tx,y=ty;}};
    inline bool cmpx(const pt &a,const pt &b){return (a.x!=b.x)?a.x<b.x:a.y<b.y;}//以x为第一关键字比较

    typedef pt vec;//vec:向量,可以直接用点表示 
    inline double Len(const vec &a){return sqrt(a.x*a.x+a.y*a.y);}//向量的模长 
    inline double angle(const vec &a){return atan2(a.y,a.x);}//向量与x轴的夹角
    inline vec operator +(const vec &a,const vec&b){return vec(a.x+b.x,a.y+b.y);}//向量加法 
    inline vec operator -(const vec &a,const vec&b){return vec(a.x-b.x,a.y-b.y);}//向量减法
    inline vec operator *(const vec &a,const double b){return vec(a.x*b,a.y*b);}//向量数量积(重载参数) 
    inline vec operator /(const vec &a,const double b){return vec(a.x/b,a.y/b);}//向量数量积的逆运算(除法)(重载参数)

    inline double operator *(const vec &a,const vec&b){return a.x*b.x+a.y*b.y;}//向量点积(重载参数)
    inline double operator ^(const vec &a,const vec&b){return a.x*b.y-a.y*b.x;}//向量叉积-忽略了方向,只保留正负(重载参数)

    inline vec rotate(vec a,double theta)//将向量绕原点逆时针旋转角theta的弧度 
    {return vec(a.x*cos(theta)-a.y*sin(theta),a.x*sin(theta)+a.y*cos(theta));}
    inline vec rotate_90(vec a){return vec(a.y,-a.x);}//向量绕原点逆时针旋转90度 
    inline pt rotate_p(pt a,pt b,double theta){return rotate(a-b,theta)+b;}//将点a绕点b旋转theta 实现方法相当于平移了坐标系 

    //命名技巧:点P(point),线段S(segment),射线R(ray),直线L(line) 
    struct line{pt s,t;line(pt ts=pt(0,0),pt tt=pt(0,0)){s=ts,t=tt;}};//两端点表示一条线段
    inline double maxx(const line &L){return max(L.s.x,L.t.x);}
    inline double minx(const line &L){return min(L.s.x,L.t.x);}
    inline double maxy(const line &L){return max(L.s.y,L.t.y);}
    inline double miny(const line &L){return min(L.s.y,L.t.y);}
    inline double angle(const line &L){return angle(L.t-L.s);}//直线与x轴的夹角(重载参数)

    inline bool operator <(const line &a,const line &b)//判断b在a的逆时针方向(b与x轴的夹角更大)则返回真 
    {
        //没有明白为什么要先判断角再用叉积判断 而且原博客似乎写错了 
        double a1=angle(a.t-a.s),a2=angle(b.t-b.s);
        if(dcmp(a2-a1)!=0) return dcmp(a2-a1)>0;
        else return dcmp((a.t-a.s)^(b.t-b.s));//似乎这里原博客错了 
    }
    inline bool operator ==(pt a,pt b){return (!dcmp(a.x-b.x))&&(dcmp(a.y-b.y));}//判断两点是否重合
    inline double dis_PP(pt a,pt b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}//两点距离
    inline bool judge_PL(pt a,line b){return !dcmp((a-b.s)^(b.t-b.s));}//判断点是否在直线上(叉积为0)
    inline bool judge_PS(pt a,line b){return (!dcmp((a-b.s)^(b.t-b.s)))&&(dcmp((a-b.s)*(a-b.t))<=0);}//判断点是否在线段上

    inline pt Footpoint(pt a,line b)//点A在直线ST上的垂足 
    {
        vec x=a-b.s,y=a-b.t,z=b.t-b.s;
        double s1=x*z,s2=-1.0*(y*z);//AS、AT在ST上的投影 | 正负必须这么处理,以解决垂足不在线段b上的情况
        return b.s+z*(s1/(s1+s2));//一次解决垂足在S左侧、线段b上、T右侧三种情况
    }
    inline pt mirror(pt a,line b){return a+(Footpoint(a,b)-a)*2.0;}//点a关于直线b的对称点
    inline double dis_PL(pt a,line b){return Abs((a-b.s)^(a-b.t))/Len(b.t-b.s);}//点到直线的距离:面积除以底边长
    inline double dis_PS(pt a,line b)//点到线段的距离 
    {
        vec x=a-b.s,y=a-b.t,z=b.t-b.s;
        if(dcmp(x*z)<0) return Len(x);//垂足在左端点左侧,a离左端点最近 
        if(dcmp(y*z)>0) return Len(y);//垂足在右端点右侧,a离右端点最近
        return dis_PL(a,b);//垂足在线段上 
    }
    inline pt point_PS(pt a,line b)//点a在线段b上距离最近的点 
    {
        vec x=a-b.s,y=a-b.t,z=b.t-b.s;
        if(dcmp(x*z)<0) return b.s;//垂足在左端点左侧,a离左端点最近 
        if(dcmp(y*z)>0) return b.t;//垂足在右端点右侧,a离右端点最近
        return Footpoint(a,b);//垂足在线段上,垂足距离最近 
    }
    inline pt cross_LL(line a,line b)//直线的交点 
    {
        vec x=a.t-a.s,y=b.t-b.s,z=a.s-b.s;
        return a.s+x*((y^z)/(x^y));//按照面积比找到交点在a上的位置,此处需要画图理解 
    }
    inline bool judge_cross_SL(line a,line b)//判断线段a和直线b是否相交
    {
        if(!dcmp((a.t-a.s)^(b.t-b.s))) return false;//线段所在直线平行
        return judge_PS(cross_LL(a,b),a);//两直线交点在a上 
    }
    inline bool judge_cross_LL(line a,line b)//判断线段a和线段b是否相交
    {
        return judge_cross_SL(a,b)&&judge_cross_SL(b,a);//线段a与直线b相交且线段b与直线a相交 | 原博客判断方法有些复杂 
    } 
}
using namespace CG;
int main()
{
	pt A,B;
	scanf("%lf%lf%lf%lf",&A.x,&A.y,&B.x,&B.y);
	printf("%.3lf",dis_PP(A,B));
	return 0; 
}

P

思路

甲流好可怕qwq。

AC code

#include<bits/stdc++.h>
using namespace std;
int a,b;
int main()
{
	scanf("%d%d",&a,&b),printf("%.3lf",100.0*b/a),cout<<"%";
}

Q

思路

略略略。

AC code

#include<bits/stdc++.h>
using namespace std;
double n;
int main()
{
	scanf("%lf",&n),printf("%.5lf",5.0*(n-32)/9);
}

R

思路

怎么还有⚪啊。

AC code

#include<bits/stdc++.h>
using namespace std;
const double pi=3.14;
double n;
int main()
{
	scanf("%lf",&n),printf("%.2lf",4.0/3*pi*n*n*n);
}