长沙学院2021校赛

比赛链接:https://ac.nowcoder.com/acm/contest/15332#question

差不多应该做出来的都补了,我可真辣鸡呀!
学过的算法还不能ac,太丢人了。。。

A.小圆前辈去上学

题目

链接:https://ac.nowcoder.com/acm/contest/15332/A
来源:牛客网

题目描述

小圆前辈刚上小学一年级,开学第一天老师就讲了对于小数如何四舍五入成整数。

例如:4.78四舍五入就是5,3.11四舍五入就是3。

现在老师让她回家写个程序, 如何将小数四舍五入成整数。

输入描述:

给你一个正实数n。

输出描述:

输出一个整数表示四舍五入后的结果。

思路

签到题,long double数存,输出%.Lf(注意long double 的输出格式为%Lf)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=0.000001;
 
int main()
{
    long double a;
    cin>>a;
    printf("%.Lf",a);
    return 0;  
}

B.小圆前辈的素数

翻博客无意间看到这场校赛的博客,顺便回来补一下这道当时的要命题。

题目

链接:https://ac.nowcoder.com/acm/contest/15332/B
来源:牛客网

题目描述

小焰同学由于在大学的时候不学无术,所学的专业知识不足矣她找到一份像样的工作,这让她很苦恼。之后的某一天她发现,中国几乎所有的科技公司都宣布开始造车,所以她觉得以后汽车维修工作这样的人才缺口一定很大,从此她发奋图强,拜师学艺,在一年后的今天当上了一名光荣的汽车维修师傅。今天是小焰同学上班的第一天,她需要修理的是一辆拥有中控异响、刹车失灵、充电异常、地库自燃等等问题的一台TSL汽车。虽然这种车况本应直接报废要求厂家退款的,但是官方说这是车主自身的问题,不予以质保。乐于助人的小焰同学决定帮一帮这位韭菜。经过问题排查后,她得到了汽车的两组电线接头,一组接头个数为 n ,另一组接头个数为 m 。每个接头都有一个数值显示,她需要将两边的接头每边选择一个进行对接,对接之后两边的数值会进行相加,如果结果为质数的话证明接对了,否则就接错了。如果仅仅是为了接对,她自己就可以解决了,但是好学的她想要知道有多少种正确的对接方式,不学无术的她因为以前训练不饱和做不来,所以请你帮帮她。

输入描述:

第一行输入一个整数t,代表样例组数。 (t ≤ 5)

对于每一组样例中:

第一行输入两个整数 n m (1≤ n, m ≤ 100000)第二行输入 n 个整数表示一边的接头示数
第三行输入 m 个整数表示另一边的接头示数
示数的范围 [1, 100000]

输出描述:

输出一个整数,表示答案。

思路

几个月再看,真是个板的不能再板的题啊!还得是龚神的教育题!

将两组接头示数出现次数存起来,

一波fft卷积操作得到两组接头示数相接之后得到的数出现的个数,

线性筛预处理两倍示数值域内的素数(相接即相加,值域翻倍)

遍历累加满足条件的数出现的个数即可。

别看代码看起来很吓人,会了之后全是板子(滑稽)

CODE

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+7;  
const double eps=1e-6;
const double PI=acos(-1.0);
struct hs
{
    double r,i;
    hs(double _r = 0,double _i = 0)
    {
        r = _r; i = _i;
    }
    hs operator +(const hs &b)
    {
        return hs(r+b.r,i+b.i);
    }
    hs operator -(const hs &b)
    {
        return hs(r-b.r,i-b.i);
    }
    hs operator *(const hs &b)
    {
        return hs(r*b.r-i*b.i,r*b.i+i*b.r);
    }
};

void change(hs y[],ll len)
{
    ll i,j,k;
    for(i = 1, j = len/2;i < len-1;i++)
    {
        if(i < j)swap(y[i],y[j]);
        k = len/2;
        while( j >= k)
        {
            j -= k;
            k /= 2;
        }
        if(j < k)j += k;
    }
}
void fft(hs y[],ll len,ll on)
{
    change(y,len);
    for(ll h = 2;h <= len;h <<= 1)
    {
        hs wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
        for(ll j = 0;j < len;j += h)
        {
            hs w(1,0);
            for(ll k = j;k < j+h/2;k++)
            {
                hs u = y[k];
                hs t = w*y[k+h/2];
                y[k] = u+t;
                y[k+h/2] = u-t;
                w = w*wn;
            }
        }
    }
    if(on == -1)
        for(ll i = 0;i < len;i++)
            y[i].r /= len;
}
ll a[N],b[N];
hs x1[N],x2[N];
ll sum[N];
ll num1[N],num2[N];
#define maxn 300007
int prime[maxn+7];
int vis[maxn+7];
void shai()
{
    for(int i=2;i<=maxn;i++)
    {
        if(!vis[i])
        {
            prime[++prime[0]]=i;
        }
        for(int j=1;j<=prime[0]&&i*prime[j]<=maxn;j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                break;
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    shai();
    while(t--)
    {
        memset(num1,0,sizeof num1);
        memset(num2,0,sizeof num2);
        int n,m;
        cin>>n>>m;
        for(int i=0;i<n;i++)
        {
            cin>>a[i];
            num1[a[i]]++;
        }
        for(int i=0;i<m;i++)
        {
            cin>>b[i];
            num2[b[i]]++;
        }
        sort(a,a+n);
        sort(b,b+m);
        int len=1;
        int len1=a[n-1]+1;
        int len2=b[m-1]+1;
        while(len<len1*2||len<len2*2)   len*=2;
        for(ll i=0;i<len1;i++)
        {
            x1[i]=hs(num1[i],0);
        }
        for(ll i=len1;i<len;i++)
        {
            x1[i]=hs(0,0);
        }
        for(ll i=0;i<len2;i++)
        {
            x2[i]=hs(num2[i],0);
        }
        for(ll i=len2;i<len;i++)
        {
            x2[i]=hs(0,0);
        }
        fft(x1,len,1);
        fft(x2,len,1);
        for(int i=0;i<len;i++)
        {
            x1[i]=x1[i]*x2[i];
        }
        fft(x1,len,-1);
        for(ll i = 0;i < len;i++)
            num1[i] = (ll)(x1[i].r+0.5);
        len=a[n-1]+b[m-1];
        ll ans=0;
        for(int i=2;i<=len;i++)
        {
            if(!vis[i])
            {
                ans+=num1[i];
                //cout<<"i="<<i<<' '<<"num1[i]="<<num1[i]<<endl;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

C.小圆前辈去爬山

待补

D.小圆前辈的魔法

题目

链接:https://ac.nowcoder.com/acm/contest/15332/D
来源:牛客网

题目描述

小焰同学很害怕虫子,每次看到会飞的昆虫也会跟着飞起来,为此小圆前辈就决定用魔法在寝室里面划定一个区域,让这个区域保持一个无虫的状态,小圆前辈施法过程是这样的:悬停在俯视图为三角形的寝室上空,画上一条边界经过寝室,将寝室分为两个部分,这样较小的区域就会成为一个没有任何虫子的区域,因为小圆前辈的室友更多是喜欢昆虫的。小圆前辈魔法虽然不能划出好友指定大小的区域,但是可以保证的是边界一定会将寝室划分成两个面积大于0的区域。现在请你计算最终小圆前辈能分出多大的区域给好友。

输入描述:

前三行每行两个整型数,代表三角形寝室的坐标

第四行四个整型数,代表边界的坐标

输出描述:

输出一行浮点数,代表小圆前辈好友得到的无虫区域面积

输出与答案误差不超过 1e-6 视为正确答案

思路

一道不算太复杂的几何题,有板子就能做,通过率误我!

总共就六种状态,分别过三个点,或者分别与两条边相交。

判断直线过顶点——叉积为0(如果是判断点在线段上还需要判断x,y在不在两个端点的中间)

判断与哪两条边相交——利用叉积的性质,判断哪两个点在同一边,即可知其两条对边与直线相交

在这里插入图片描述

三角形面积——叉积/2.0 的绝对值

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200007
#define MAXN 110
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=0.000001;
#define mod 1000000007;
struct Point
{
    double x,y;
    Point(){}
    Point(double xx,double yy){
        x=xx,y=yy;
    }
};
struct Line {
    Point a, b;
    Line(Point aa,Point bb){
        a=aa,b=bb;
    }
};
double Cross(Point p1,Point p2,Point p3){
    return (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x);
}
double dot_mul(Point p1,Point p2,Point p0){
    return (p1.x-p0.x) * (p2.y-p0.y) - (p2.x-p0.x) * (p1.y-p0.y);
}
double Dis(Point A, Point B){
    return sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y));
}
bool dot_in_online(Point a,Line b)
{
    if(fabs(dot_mul(a,b.a,b.b))<eps)
        return 1;
    return 0;
}
Point GetLineIntersection(Line u,Line v) {
    Point ret = u.a;
    double t = ((u.a.x-v.a.x) * (v.a.y-v.b.y) - (u.a.y-v.a.y) * (v.a.x-v.b.x)) / ((u.a.x-u.b.x) * (v.a.y-v.b.y) - (u.a.y-u.b.y) * (v.a.x-v.b.x));
    ret.x += (u.b.x - u.a.x) * t;
    ret.y += (u.b.y - u.a.y) * t;
    return ret;
}
Point operator - (Point A,Point B){
    return Point(A.x-B.x, A.y-B.y);
}
Point operator + (Point A, Point B){
    return Point(A.x+B.x, A.y+B.y);
}
Point operator * (Point A, double p){
    return Point(A.x*p, A.y*p);
}
bool operator == (Point A, Point B){
    return (A.x-B.x) == 0 && (A.y-B.y) == 0;
}
int main() 
{
    Point a,b,c,d,e;
    int x,y;
    cin>>x>>y;
    a=Point(x,y);
    cin>>x>>y;
    b=Point(x,y);
    cin>>x>>y;
    c=Point(x,y);
    double mj=fabs(Cross(a,b,c)/2.0);
    //cout<<mj<<endl;
    cin>>x>>y;
    d=Point(x,y);
    cin>>x>>y;
    e=Point(x,y);
    Line l=Line(d,e);
    if(dot_in_online(a,l))//过a点
    {
        Point f=GetLineIntersection(l,Line(b,c));
        double mjj=fabs(Cross(f,a,c)/2.0);
        //cout<<mjj<<endl;
        printf("%.10lf\n",min(mj-mjj,mjj));
    }
    else if(dot_in_online(b,l))//过b点
    {
        Point f=GetLineIntersection(l,Line(a,c));
        double mjj=fabs(Cross(f,b,c)/2.0);
        
        printf("%.10lf\n",min(mj-mjj,mjj));
    }
    else if(dot_in_online(c,l))//过c点
    {
        Point f=GetLineIntersection(l,Line(a,b));
        double mjj=fabs(Cross(f,a,c)/2.0);
        
        printf("%.10lf\n",min(mj-mjj,mjj));
    }
    else
    {
        double mmj;
        if(Cross(a,l.a, l.b)*Cross(b,l.a, l.b) > eps)//过a,b边
        {
            Point xx1 = GetLineIntersection(l, Line(a,c));
            Point xx2 = GetLineIntersection(l, Line(b,c));
            mmj = fabs(Cross(xx1, xx2, c)/2.0);
        }
        else if(Cross(c,l.a, l.b)*Cross(b,l.a, l.b) > eps)过c,b边
        {
            Point xx1 = GetLineIntersection(l, Line(a,c));
            Point xx2 = GetLineIntersection(l, Line(a,b));
            mmj = fabs(Cross(xx1, xx2, a)/2.0);
        }
        else if(Cross(a,l.a, l.b)*Cross(c,l.a, l.b) > eps)过a,c边
        {
            Point xx1 = GetLineIntersection(l, Line(a,b));
            Point xx2 = GetLineIntersection(l, Line(b,c));
            mmj = fabs(Cross(xx1, xx2, b)/2.0);
        }
        printf("%.10lf\n",min(mj-mmj,mmj));
    }
    return 0;
}

E.小圆前辈的排列组合

题目

链接:https://ac.nowcoder.com/acm/contest/15332/E
来源:牛客网

题目描述

小焰同学是小圆前辈的好朋友,她已经在CCSU生活三年了,别看她现在是在ACM实验室,其实在之前她一直忙于各种社团与班级团建活动之中,还在兼顾学习成绩与竞赛强度的她有一些力不从心,尤其是大一的时候因为社团的节目排练还占用了她大部分时间,甚至影响了正常作息,让她在接下来的大学生活一直处于阴影之中。作为她的室友因为长期收到这样的负面情绪而苦不堪言。所以为了让她训练饱和,想要帮她在之后的日子中去除那些琐碎的杂事,只挑有意义的事情让她做,现在我们把所有的事件比作一个长度为 n 的的字符串,每一件事情是一个字符。她在第合数个事件中想要划水看番打游戏,所以你只能从素数事件中挑选事件来让她做,其中如果在所有挑选的事件中可以重新排列组合成为“ CCSU ” 的话,证明她做的事情是有意义的,那么请问在这一系列的事情中她是否可以做有意义的事呢,可以的话输出 “Yes”,否则输出 “No”。(字符串从一开始)

输入描述:

仅包含一行字符串 s

每个字符可能为数字或者大小写字母

输出描述:

如果小焰同学可以做有意义的事情

输出 “Yes”

否则输出 “No”

(不带引号)

思路

​ 筛选出来素数(埃氏筛表示完全能担此重任!),将素数位出现的’C’,‘S’,'U’的数量存下来,判断是否能组成“CCSU”即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=0.000001;
int vis[1000007];
void init()
{
	vis[1]=1;
	for(int i=2;i<=1000000;i++)
	{
		if(!vis[i])
		for(int j=i+i;j<=1000000;j+=i)
		{
			vis[j]=1;
		}
	}
}
int a[5];
int main()
{
	init();
	string s;
	cin>>s;
	int si=s.size();
	for(int i=0;i<si;i++)
	{
		if(!vis[i+1])
		{
			if(s[i]=='C')
			{
				a[1]++;
			}
			if(s[i]=='S')
			{
				a[2]++;
			}
			if(s[i]=='U')
			{
				a[3]++;
			}
		}
	}
	if(a[1]>=2&&a[2]>=1&&a[3]>=1)
		printf("Yes\n");
	else
		printf("No\n");
    return 0;
}

F.小圆前辈的数组Ⅱ

题目

链接:https://ac.nowcoder.com/acm/contest/15332/F
来源:牛客网

题目描述

在你的帮助下,小圆前辈成功破译了这个长为n的数组。原来这个数组是小焰同学上周送给她的,并安排小圆前辈帮她算出数组中的最长完美子序列的长度,可是粗心的小圆前辈忘记了。小圆前辈现在再一个一个找已经来不及了,于是便求助于你,你能帮她算出最长完美子序列的长度吗?

我们定义一个序列是完美的:对于所有的1≤i<n1 \le i < n1≤i<n,满足b[i]不是b[i + 1]的因数。

子序列的定义:a是 b的子序列, 当且仅当可以从b中删除一些元素得到a。

输入描述:

第一行只有三个整数n。第一行共n个整数a[1]~a[n]。

输出描述:

一个整形数表示答案。

思路

涛哥一番点拨,我悟了!赞美涛哥!

还是当最长上升序列的变式来做,我就认为是贪心,涛哥说不是那就不是吧毕竟我是个菜鸡┭┮﹏┭┮

最先想到的还是两层for循环,dp[i]=max(dp[i],dp[j]+1),不出意料的超时。

做这题时想过去记录最大的dp[j]值,但因为可能a[j]是a[i]的因子,无奈放弃这一思路。

但是看到涛哥用了个set优化,不禁感叹涛哥是TN是个天才。

具体优化思路就是

1、记录不同a[i]值所在位置的dp值,不断往后遍历,如果出现相同的a[i]值如果所在dp值更大就将其更新。(因为相同值的话我肯定从最大dp值的位置跳到当前位置)

2、第二层for循环如果从第i个遍历到最后一个会超时,但使用set排序后,从dp值最大的位置往dp值最小的位置遍历就可以有效的减少复杂度。同时因为给定数据最大为1e5,所以最多因子的情况也就一百来个,遍历不了多少次,运算次数至少缩小几十倍。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=0.000001;
#define mod 998244353723;
int a[100007];
int dp[100007],ma[100007];
set<pii,greater<pii>>s;
int ans=0;
int main()
{
	int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        dp[i]=1;
        for(auto it: s)//因为给定数据最大1e5,所以最多因子的情况也就一百来个,所以遍历不了多少次!!!set妙极
        {
            if(a[i]%a[it.second])
            {
                dp[i]=it.first+1;
                break;
            }
        }
        if(!ma[a[i]])//第一次出现a[i]
        {
            s.insert(pii(dp[i],i));
            ma[a[i]]=i;
        }
        else
        {
            if(dp[ma[a[i]]]<dp[i])//如果此时的a[i]的dp值大于上一个a[i],就需要更新一下,否则无所谓选择哪一个a[i]
            {
                s.erase(pii(dp[ma[a[i]]],ma[a[i]]));
                s.insert(pii(dp[i],i));
                ma[a[i]]=i;
            }
        }
        ans=max(ans,dp[i]);
    }
    cout<<ans<<endl;
    return 0;
}

G.小圆前辈的数组

题目

链接:https://ac.nowcoder.com/acm/contest/15332/G
来源:牛客网

题目描述

小圆前辈最近收到了一个长度为n数组。她怀疑是不怀好意的魔女给她的陷阱,于是她对数组进行了剖析后发现了两个关键的整数k和z,而解读此数组只要算出的所有连续子序列中有多少满足:

1,所有数的和为k的倍数;

2,且其和至少为z;

这个问题难到了小圆前辈,她便把这个问题交给了你,如果你能帮她解决的话,她将奖励你一个Accept。

输入描述:

第一行只有三个整数n,k,z。第一行共n个整数a[1]~a[n]。

输出描述:

一个整形数表示答案。

思路

直接暴力两层循环必然超时。不要想遍历!想都不要想!怎么会优化都不要想!!!血泪史。。。

普及一个实用小技巧,不会二分怎么办,懒得写二分怎么办!upper_bound(),lower_bound()你值得拥有。(赞美涛哥!)

当然,必须是在排好序的数组。(二分当然是在顺序的数组查找,废话

lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。

这道题讨论的是一个连续序列的和,那么我们可以在vector内依次存放前缀和(单调递增)

怎么存放前缀和呢?

我们已知的,存在两个k的倍数a,b(a<b),有(b-a)%k==0.

那么我们就可以将前缀和存入下标为前缀和模上k的容器

v[a[i]%k].push_back(a[i]);

接下来我们只要知道从哪一个数开始b-a<z的,就能判断a之前的数都符合题意。

于是,代码↓(注意int会爆数据)

代码

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
double PI=acos(-1.0);
#define ll long long
const double eps=0.000000001;
const ll mod=1e9+7;
ll a[100007];
vector<ll>v[100007];
ll ans=0;
int main()
{
    ll n,k,z;
    cin>>n>>k>>z;
    for(ll i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        a[i]+=a[i-1];
        v[a[i]%k].push_back(a[i]);
    }
    for(ll i=1;i<=n;i++)
    {
        if(a[i]<z)  continue;
        if(a[i]%k==0)   ans++;
        ll p=a[i]-z;
        ll tot=a[i]%k;
        ll num=upper_bound(v[tot].begin(),v[tot].end(),p)-v[tot].begin();
        ans+=num;
    }
    cout<<ans<<endl;
    return 0;
}

H.小圆前辈的博弈

题目

链接:https://ac.nowcoder.com/acm/contest/15332/H
来源:牛客网

题目描述

小圆前辈今天将小焰同学叫来了,她们在玩一个有趣的游戏。小圆前辈有一个长度为n的字符串S,小焰有一个长度为m的字符串T,游戏规则是这样的:首先小圆前辈从S中取出一个子串s,然后小焰从T中取出一个子串t,若s与t相等的话,小圆前辈就输了,否则小焰输。小圆前辈想知道她有多少种必胜的取法,并向你求助,你能告诉她吗?

​ 对于取出的任意的两个子串,只要在原串中位置不同我们就认为是不同的取法。 例如:abab中12的ab与34的ab虽然子串一样,但我们认为是不同的取法。

输入描述:

第一行两个整数n,m分别表示S的长度与T的长度。第二行一个字符串S。第三行一个字符串T。

输出描述:

一个整数表示答案。

思路

这题真给自己蠢哭了,再优化一点就过了,第一次卡常再不想回想

不可我一人感受绝望

在这里插入图片描述

都不用map,我就用!!!我就头铁!标准答案好像是用字典树,到时候再写一次

当然不能简单的使用map,各位如果使用map超时时也可换一个容器unordered_map.具体细节自行百度,反正使用上和map基本没啥区别(只是有一次好像之前用这个里面存pair不进去)

直接往map里存string也是不行的,TLE套餐。需要把string哈希一下,字母有26位,就乘26以上的数字(如27)下一位加的数字就不会影响到上一位了。(友情提示,mod开大一点).

这道题我的实现也很暴力,就是把小焰的字符串的所有字串存进map,再查找小圆前辈的字符串的每个字串就行了。唯一注意的就是!!!一旦小圆前辈的一个字串被检查出小焰没有,代表出现了小焰字符串中没有的字母,那么从该字母遍历到最后一个字母的这些字串小焰都是没有的,可以直接加上跳出循环!!!(就卡这点常气死我)

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=0.000001;
#define mod 998244353723;
int n,m;
unordered_map<ll,int>m1;
int main()
{
	cin>>n>>m;
	string s,s1;
	cin>>s>>s1;
	ll num=0;
	for(int i=0;i<m;i++)
	{
		ll p=0;
		for(int j=i;j<m;j++)
		{
			p=(p*27+(s1[j]-'a'+1))%mod;
			m1[p]=1;
		}
	}
	for(int i=0;i<n;i++)
	{
		ll p=0;
		for(int j=i;j<n;j++)
		{
			p=(p*27+(s[j]-'a'+1))%mod;
			if(m1[p]!=1)
            {
				num+=n-j;
                break;
            }
		}
	}
	cout<<num<<endl;
}

I.小圆前辈的暴力枚举

题目

链接:https://ac.nowcoder.com/acm/contest/15332/I
来源:牛客网

题目描述

小圆前辈家有一个n * m的矩阵,对于矩阵上的每一个格子,你都可以放置一个棋子(易知总共有2n∗m2^{n *m}2n∗m种放置情况)。小圆前辈想知道,在所有放置情况中有多少种情况满足:对于矩阵的每一行且每一列至多只有1个棋子。小圆前辈一想,这不是暴力枚举一下就行了,于是便把问题交给你了,你能求出答案是多少吗。

结果对998244353取模。

输入描述:

一行只有两个整数,n和m。

输出描述:

一个整形数表示答案。

思路

很“洋神”的题!数位DP吧,具体看图

在这里插入图片描述

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pii pair<int,int>
const double PI=acos(-1.0);
const double eps=0.000001;
#define mod 998244353;
ll f[1007][1007];
ll n,m;
void init()//求组合数
{
	for(int i=0;i<=1000;i++)
		for(int j=0;j<=i;j++)
		{
			if(!j)	f[i][j]=1;
			else	f[i][j]=(f[i-1][j]+f[i-1][j-1])%mod;
		}
}
ll dp()
{
	ll res=0;
	ll last=0;
	for(int i=n;i>=1;i--)
	{
		for(int j=0;j<=i-1&&j<m;j++)
		{
			ll ans=1;
			for(int k=m,l=1;l<=j+1&&k>1;k--,l++)
				ans=ans*k%mod;
			res=(res+f[i-1][j]*ans)%mod;
		}
	}
	
	return res;
}
int main()
{
	init();
	cin>>n>>m;
	cout<<dp()+1<<endl;//存在一个1都不放的情况所以要+1
}

代码很丑我知道我知道,别骂了别骂了。。。o…orz

J.小圆前辈的异或树

树上启发式到时候再补一下

K.小圆前辈的888

不会

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

第十页

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值