2015 ACM/ICPC Asia Regional Changchun Online

本文精选了一系列关于算法、编程技术和软件开发的文章,涵盖了从基础到高级的多个领域,包括数据结构、算法、人工智能、测试、运维等。文章深入浅出地讲解了各种技术原理和实践应用,适合开发者和技术爱好者阅读。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

更新中.......

<题目链接>

A.Alisha's Party (模拟+优先队列)

题意:Alisha 他邀请了她的朋友参加她的生日party,每个朋友将会给她带一份礼物。由于她的院子不够大,每次他的某个朋友来了之后她就会开门同时放p个人进来(假如外面没有p个人,就把外面的所有人放进来),进来的顺序按礼物的价值由搞到低进,价值相同的则按来的先后顺序进。当最后一个朋友来了之后,就会将所有没有进来的人全部放进去。现在问你q次,每次问你第x个进来的人是谁。

分析:用优先队列直接模拟就好了。注意最后要把所有的人放进来。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 2e5+6;
struct node
{
    int v,id;
    bool operator < (const node & t)const
    {
        if(v!=t.v)
            return v<t.v;
        return id>t.id;
    }
}s[maxn];
char name[maxn][202];
pair <int ,int > p[maxn];
priority_queue <node > que;
int ans[maxn];

int main()
{
    int ncase,n,k,m,i,j,x,y,q;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d%d%d",&k,&m,&q);
        for(i=1;i<=k;i++)
        {
            scanf("%s%d",name[i],&s[i].v);
            s[i].id=i;
        }

        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            p[i]=make_pair(x,y);
        }
        sort(p+1,p+m+1);
        
        int cur=1,cnt=1,num=0;
        for(i=1;i<=m;i++)
        {
            while(cur<=k && cur<=p[i].first)
                que.push(s[cur++]);
            num=p[i].second;
            while(num-- && !que.empty())
            {
                ans[cnt++]=que.top().id;
                que.pop();
            }
        }
        while(cur<=k)
            que.push(s[cur++]);
        while(!que.empty())
        {
            ans[cnt++]=que.top().id;
            que.pop();
        }
        scanf("%d",&x);
        printf("%s",name[ans[x]]);
        for(i=2;i<=q;i++)
        {
            scanf("%d",&x);
            printf(" %s",name[ans[x]]);
        }
        printf("\n");
    }
    return 0;
}

B.Ponds(并查集)

题意:给定一个图,将图中所有度小于2的顶点去掉,知道图里面没有度小于2的顶点为止。求剩余的顶点的权值之和(注意题目要求剩余顶点所在的子图里面顶点数目为odd)。

分析:类似拓扑排序,每次去掉度为1的顶点,同时更新并查集。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 2e5+6;
struct node
{
    int v,id;
    bool operator < (const node & t)const
    {
        if(v!=t.v)
            return v<t.v;
        return id>t.id;
    }
}s[maxn];
char name[maxn][202];
pair <int ,int > p[maxn];
priority_queue <node > que;
int ans[maxn];

int main()
{
    int ncase,n,k,m,i,j,x,y,q;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d%d%d",&k,&m,&q);
        for(i=1;i<=k;i++)
        {
            scanf("%s%d",name[i],&s[i].v);
            s[i].id=i;
        }

        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&x,&y);
            p[i]=make_pair(x,y);
        }
        sort(p+1,p+m+1);
        
        int cur=1,cnt=1,num=0;
        for(i=1;i<=m;i++)
        {
            while(cur<=k && cur<=p[i].first)
                que.push(s[cur++]);
            num=p[i].second;
            while(num-- && !que.empty())
            {
                ans[cnt++]=que.top().id;
                que.pop();
            }
        }
        while(cur<=k)
            que.push(s[cur++]);
        while(!que.empty())
        {
            ans[cnt++]=que.top().id;
            que.pop();
        }
        scanf("%d",&x);
        printf("%s",name[ans[x]]);
        for(i=2;i<=q;i++)
        {
            scanf("%d",&x);
            printf(" %s",name[ans[x]]);
        }
        printf("\n");
    }
    return 0;
}

C.Aggregated Counting (OEIS+离线处理)

题意:给定序列a[1...oo]=1、2、2、3、3、4、4、4.......规律是加a[cur]个cur(cur表示当前值的大小)。比如再往后接,就是接3个5,再接4个6......,给定整数n,最后一个n的位置p1,最后一个p1的位置p2,求p2。比如n=3,最后一个3的位置是5,最后一个5的位置是11,那么答案就是11。

分析:先写个暴力版本的,把前面的几个数丢到OEIS.......发现有公式!!!公式:sigma{i*a[i],1<=i<=n},将和式压缩求解,比如n=3,ans=1*1+(2+3)*2。但是,复杂度为q*sqrt(n),数据比较多,发现计算小的对大的数有帮助,离线处理就好了。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 1e6+6;
const LL mod = 1000000007;
int a[maxn],cur;

struct node
{
    int id,x;
    bool operator < (const node &t)const
    {
        return x<t.x;
    }
}q[10000];
LL ans[10000];

void Init()
{
    cur=3;
    int p=4;
    a[1]=1;
    a[2]=2;
    a[3]=2;
    while(1)
    {
        for(int j=1;j<=a[cur] && p<maxn-1;j++)
            a[p++]=cur;
        cur++;
        if(p>=maxn-1)
            break;    
    }
}
int Find(int x)
{
    int pos1=lower_bound(a,a+maxn,x+1)-a-1;
    return lower_bound(a,a+maxn,pos1+1)-a-1;
}

inline LL cal(LL s,LL x)
{
    return (s+s+x-1)*x/2%mod;
}
int getAns(int x)
{
    LL cur=1,len=0,L=0;
    LL ret=0;
    while(L<x)
    {
        if(L+a[cur]<=x)
        {
            ret=(ret+cur*cal(L+1,a[cur]));
            if(ret>mod)
                ret%=mod;
            L+=a[cur];
            cur++;
        }
        else
        {
            ret=(ret+cur*cal(L+1,x-L));
            if(ret>mod)
                ret%=mod;
            L=x;
        }
    }
    //printf("cur:%lld \n",cur);
    return int(ret);
}

void getall(int n)
{
    LL cur=1,L=0;
    LL ret=0;
    for(int i=0;i<n;i++)
    {
        while(L<q[i].x)
        {
            if(L+a[cur]<q[i].x)
            {
                ret=(ret+cur*cal(L+1,a[cur]))%mod;
                L+=a[cur];
                cur++;
            }
            else
            {
                ans[q[i].id]=(ret+cur*cal(L+1,q[i].x-L))%mod;
                break;
            }
        }
    }
}

int main()
{
//    freopen("test.txt","r",stdin);
//    freopen("h.txt","w",stdout);
    Init();
    int ncase,x;
    scanf("%d",&ncase);
    for(int i=0;i<ncase;i++)
    {
        scanf("%d",&q[i].x);
        q[i].id=i;
    }
    sort(q,q+ncase);
    getall(ncase);
    for(int i=0;i<ncase;i++)
        printf("%lld\n",ans[i]);
    return 0;
}


D.Clock Adjusting(待更新)


E.Travel(并查集+离线处理)

题意:给定一个图,有q次查询,每次查询给定一个整数x,问图里面有多少点对(u,v),(u,v)要满足:u<-->v这条路径上的相邻点的路径的权值不大于x。

分析;将边按权值由小到大排序。每查询一次,往图里面添加权值不大于x的边。每个子图就是一个集合,用并查集维护,动态更新答案。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 2e5+6;
int fa[maxn],sz[maxn];
LL ans[maxn];
struct node
{
    int a,b,v;
    bool operator < (const node &t)const
    {
        return v<t.v;
    }
}s[maxn];

struct que
{
    int id,x;
    bool operator < (const que &t)const
    {
        return x<t.x;
    }
}query[maxn];

int Find(int rt)
{
    if(fa[rt]==rt)
        return rt;
    return fa[rt]=Find(fa[rt]);
}
inline LL cal(LL n)
{
    if(n<2)
        return 0;
    return n*(n-1)>>1;
}
void Init(int lim)
{
    for(int i=1;i<=lim;i++)
    {
        fa[i]=i;
        sz[i]=1;
    }
}
LL cur;
void update(int a,int b)
{
    int root1=Find(a),root2=Find(b);
    if(root1==root2)
        return ;
    cur-=cal(sz[root1])*2;
    cur-=cal(sz[root2])*2;
    fa[root1]=root2;
    sz[root2]+=sz[root1];
    sz[root1]=0; 
    cur+=cal(sz[root2])*2;
}

int main()
{
    int ncase,n,m,i,j,x,y,v,q;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d%d%d",&n,&m,&q);
        Init(n);
        for(i=1;i<=m;i++)
            scanf("%d%d%d",&s[i].a,&s[i].b,&s[i].v);
        sort(s+1,s+m+1);
        for(i=1;i<=q;i++)
        {
            scanf("%d",&query[i].x);
            query[i].id=i;
        }
        sort(query+1,query+q+1);
        j=1;
        cur=0;
        for(i=1;i<=q;i++)
        {
            for(;j<=m && s[j].v<=query[i].x;j++)
                update(s[j].a,s[j].b);
            ans[query[i].id]=cur;
        }
        for(i=1;i<=q;i++)
            printf("%lld\n",ans[i]);
    }
    return 0;
}


F.Favorite Donut(后缀数组)

题意:给定长度为n的字符串s(s是环),然后以某一点顺时针或者逆时针出发遍历字符串s将得到一个t,求一个字典序最大的字符串t的起始位置。字典序相同的选起始位置靠前的,位置相同的选顺时针的。

分析:将原来的字符串添加字符,使得前n个字符,每个字符与其后面的n-1个字符正是循环遍历的字符串。比如aabca--->aabcaaabc (顺时针) aabca---->acbaaacba (逆时针),然后对新构造出来的字符串求其后缀数组,那么可以得到字典序最大的两个字符串(两个方向),把字符串取出来,然后比较一下就行了。

ps:对于顺时针的字符串末尾要加一个表示负无穷的字符。这样保证后缀suffix(i)与suffix(j)的LCP等于其中一个后缀的时候,位置靠前的优先选择。

对于逆时针的字符串末尾要加一个表示正无穷的字符。这样保证后缀suffix(i)与suffix(j)的LCP等于其中一个后缀的时候,位置靠后的优先选择。这里的靠后是反转之后的字符串,再反过来就是靠前的了。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
using namespace std;
const int maxn = 1e5+6;
char in[maxn],s[maxn];
int sa[maxn],t[maxn],t2[maxn],c[maxn],n;
void build_sa(int n,int m)
{
	int i,*x=t,*y=t2;
	for(i=0;i<m;i++)	c[i]=0;
	for(i=0;i<n;i++)	c[x[i]=s[i]]++;
	for(i=1;i<m;i++)	c[i]+=c[i-1];
	for(i=n-1;i>=0;i--)	sa[--c[x[i]]]=i;
	for(int k=1;k<=n;k<<=1)
	{
		int p=0;
		for(i=n-k;i<n;i++)	y[p++]=i;
		for(i=0;i<n;i++)	if(sa[i]>=k)	y[p++]=sa[i]-k;
		for(i=0;i<m;i++)	c[i]=0;
		for(i=0;i<n;i++)	c[x[y[i]]]++;
		for(i=1;i<m;i++)	c[i]+=c[i-1];
		for(i=n-1;i>=0;i--)	sa[--c[x[y[i]]]]=y[i];
		swap(x,y);
		p=1;
		x[sa[0]]=0;
		for(i=1;i<n;i++)
			x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
		if(p>=n)	break;
		m=p;
	}
}
void GetSuffix(char buf[],char str[],int p,int n)
{
	for(int cnt=0,i=p;cnt<n;cnt++,i++)
		buf[cnt]=str[i];
	buf[n]='\0';
}
char ts[maxn],s1[maxn],s2[maxn];
int main()
{
	int ncase,n,i,j,p1,p2,len1,len2;
	scanf("%d",&ncase);
	while(ncase--)
	{
		scanf("%d%s",&n,in);
		strcpy(ts,in);
		for(i=0;i<n-1;i++)
			ts[n+i]=ts[i];
		ts[n+i]='\0';
		len1=strlen(ts);
		strcpy(s,ts);
		build_sa(len1+1,255);
		for(i=len1;i>=0 && sa[i]>=n;i--);p1=sa[i];
		GetSuffix(s1,ts,p1,n);
		
		strcpy(ts,in);
		reverse(ts,ts+n);
		for(i=0;i<n-1;i++)
			ts[n+i]=ts[i];
		ts[n+i]='\0';
		len2=strlen(ts);
		ts[len2]='z'+1;
		strcpy(s,ts);
		build_sa(len2+1,255);
		for(i=len2;i>=0 && sa[i]>=n;i--) ;p2=sa[i];
		GetSuffix(s2,ts,p2,n);	
	//	printf("%s\n%s\n",s1,s2);
		p1=p1+1;
		p2=n-p2;
		int temp=strcmp(s1,s2);
		if(temp!=0)
			temp==1?printf("%d 0\n",p1):printf("%d 1\n",p2);
		else if(p1!=p2)
			p1<p2?printf("%d 0\n",p1):printf("%d 1\n",p2);
		else
			printf("%d 0\n",p1);
	}
	return 0;
}

G.The Water Problem (暴力)

题意:查询区间最大值,数据范围很小。

分析直接暴力查询就好,比赛的时候没看数据范围,用的线段树。。。。。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
int a[1005];
int main()
{
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        int n,q,i,j,m,l,r;
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        scanf("%d",&q);
        while(q--)
        {
            m=-(1<<30);
            scanf("%d%d",&l,&r);
            for(i=l;i<=r;i++) if(a[i]>m)
                m=a[i];
            printf("%d\n",m);
        }
    }
    return 0;
}


H. Elven Postman(二叉树)

题意:给定一棵排序二叉树的先序遍历,给定整数x,求从根节点到x的路径。

分析:暴力模拟。先把树建起来,然后由于是排序二叉树,直接走就行了。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
const LL INF = 1E9+9;
const int maxn = 1005;
struct node
{
    int v;
    node *lson,*rson;
    node()
    {
        lson=rson=nullptr;
    }
    node(int x,node *l=nullptr,node *r=nullptr)
    :v(x),lson(l),rson(r) {}
};
int a[maxn];

node* build(int x,int y)
{
    if(x>y)
        return nullptr;
    if(x==y)
        return new node(a[x]);
    int cur=x+1;
    while(cur<=y && a[cur]<a[x])
        cur++;
    node *L=build(x+1,cur-1);
    node *R=build(cur,y);
    return new node(a[x],L,R);
}

void check(node *root)
{
    if(root!=nullptr)
    {
        check(root->lson);
        printf("%d ",root->v);
        check(root->rson);
    } 
}

void print(node *root,int x)
{
    if(x==root->v)
        return ;
    if(x<root->v)
    {
        putchar('E');
        print(root->lson,x);
    }
    else
    {
        putchar('W');
        print(root->rson,x);
    }
}

int main()
{
    int ncase,n,q,i,j,x;
    scanf("%d",&ncase);
    while(ncase--)
    {
        scanf("%d",&n);
        for(i=1;i<=n;i++)
            scanf("%d",&a[i]);
        node *root=build(1,n);
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d",&x);
            if(root->v==x)
            {
                puts("");
                continue ;
            }
            print(root,x);
            puts("");
        }
    } 
    return 0;
}


I.Food Problem(待更新)


J.Unknow Treasure(lucas+crt)

题意:求C(n,m)%M,M<10^18。M=p1*p2.....pk,(1<=k<=10)and (pi<100 000,pi is  s prime)。

分析:直接用lucas求出C(n,m)%pi的值,然后用中国剩余定理把这些值合并。可惜啊,模版题不会,要不然当时就出线了。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

const int N =150000;

LL fac[N];

void init(LL p)
{
    int i;
    fac[0] =1;
    for(i =1; i <= p; i++)
        fac[i] = fac[i-1]*i % p;
}

LL mul(LL a,LL b,LL p)
{
    if(a==0 || b==0)
        return 0;
    int fg=1;
    if(a<0 && b<0)
    {
        a=-a;
        b=-b;
    }
    else if(a<0 || b<0)
    {
        if(a<0)
            a=-a;
        else
            b=-b;
        fg=-1;
    }
    LL ret(0);
    while(b)
    {
        if(b&1)
            ret=(ret+a)%p;
        a=(a<<1)%p;
        b>>=1;
    }
    return ret*fg;
}

LL myPow(LL a,LL n,LL p)
{
    LL ret=1;
    while(n)
    {
        if(n&1)
            ret=mul(ret,a,p);
        n>>=1;
        a=mul(a,a,p);
    }
    return ret;
}

LL C(LL n,LL m,LL p)
{
    if(m > n)  return 0;
    return  fac[n]*myPow(fac[m]*fac[n-m], p-2,p)%p;
}

LL Lucas(LL n, LL m,LL p)
{
    if(m ==0)  return 1;
    else return  (C(n%p, m%p,p)*Lucas(n/p, m/p,p))%p;
}

LL r[100],mo[100];
void gcd(LL a,LL b,LL &d,LL &x,LL &y)
{
    if(!b)
    {
        d=a;
        x=1;
        y=0;
        return ;
    }
    gcd(b,a%b,d,y,x);
    y-=x*(a/b);
}

LL china(int n)   //x=r[i] (mod m[i])
{
    LL M=1;
    LL i,Mi,x,y,d,ans=0;
    for(i=1;i<=n;i++)
        M*=mo[i];
    for(i=1;i<=n;i++)
    {
        Mi=M/mo[i];
        gcd(Mi,mo[i],d,x,y);
        //printf("%lld %lld %lld \n",Mi,x,r[i]);
        LL temp=mul(Mi,x,M);
        temp=mul(temp,r[i],M);
        ans=(ans+temp+M)%M;
      //  ans=(ans+Mi*x*r[i])%M;
    }
    return (ans+M)%M;
}

int main()
{
    int t,k,i,j;
    scanf("%d",&t);
    while(t--)
    {
        LL n,m,p;
        scanf("%lld%lld%d",&n,&m,&k);
        for(i=1;i<=k;i++)
        {
            scanf("%lld",&p);
            init(p);
            r[i]=Lucas(n,m,p);
            mo[i]=p;    
        }                                                                                                                                                        
        printf("%lld\n",china(k));
    }
    return 0;
}

K.Good Numbers(待更新)


L.Marisa's Cake(待更新)


M.Robot Dog(待更新)


资源下载链接为: https://pan.quark.cn/s/67c535f75d4c 在机器人技术中,轨迹规划是实现机器人从一个位置平稳高效移动到另一个位置的核心环节。本资源提供了一套基于 MATLAB 的机器人轨迹规划程序,涵盖了关节空间和笛卡尔空间两种规划方式。MATLAB 是一种强大的数值计算与可视化工具,凭借其灵活易用的特点,常被用于机器人控制算法的开发与仿真。 关节空间轨迹规划主要关注机器人各关节角度的变化,生成从初始配置到目标配置的连续路径。其关键知识点包括: 关节变量:指机器人各关节的旋转角度或伸缩长度。 运动学逆解:通过数学方法从末端执行器的目标位置反推关节变量。 路径平滑:确保关节变量轨迹连续且无抖动,常用方法有 S 型曲线拟合、多项式插值等。 速度和加速度限制:考虑关节的实际物理限制,确保轨迹在允许的动态范围内。 碰撞避免:在规划过程中避免关节与其他物体发生碰撞。 笛卡尔空间轨迹规划直接处理机器人末端执行器在工作空间中的位置和姿态变化,涉及以下内容: 工作空间:机器人可到达的所有三维空间点的集合。 路径规划:在工作空间中找到一条从起点到终点的无碰撞路径。 障碍物表示:采用二维或三维网格、Voronoi 图、Octree 等数据结构表示工作空间中的障碍物。 轨迹生成:通过样条曲线、直线插值等方法生成平滑路径。 实时更新:在规划过程中实时检测并避开新出现的障碍物。 在 MATLAB 中实现上述规划方法,可以借助其内置函数和工具箱: 优化工具箱:用于解决运动学逆解和路径规划中的优化问题。 Simulink:可视化建模环境,适合构建和仿真复杂的控制系统。 ODE 求解器:如 ode45,用于求解机器人动力学方程和轨迹执行过程中的运动学问题。 在实际应用中,通常会结合关节空间和笛卡尔空间的规划方法。先在关节空间生成平滑轨迹,再通过运动学正解将关节轨迹转换为笛卡
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值