每一年都奔走在自己热爱里

没有人是一座孤岛,总有谁爱着你

AtCoder Beginner Contest 207(D,E)

AtCoder Beginner Contest 207(D,E)

D(计算几何)

D

这个题是两个点的集合,每个集合有n个点,我们可以让一个集合中的每一个点进行下面两种操作

1,可以让每一个点进行旋转x的角度

2,可以让每一个点的x变成x+disx,y变成了y+disy

问是否可以让这两个集合重合(两个集合之间的点一一重叠)

对于这么两个集合,我们可以首项让这些点的重心都处于原点上

对于求重心corexcorey,是每一个点的xy的平均值

然后以a[1]这一点作为基准,判断要让b[j]这一个点和这一点可以重合,我们需要求出使重合需要旋转的角度

所以我们需要知道这两个点的角度

atan2(y,x)是求点x,y到原点这一线段和x轴之间的角度

所以我们要保证a[1]这一个不能是原点

然后对于要旋转的角度,就是atan2(a[1]y,a[1]x)atan2(b[j]y,a[j]x)

我们要怎么求一个点在旋转angle之后的坐标呢

坐标为

tx=x×sin(angle)y×cos(angle)

ty=y×cos(angle)+y×sin(angle)

具体推导

然后对于其他的点,只要a点集合有一点可以和它重合即可(因为点集合里面的每一个点都是不一样的)

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <bitset>
#include <unordered_map>
using namespace std;
const int maxn=200+10;
const int mod= 998244353;
const double eps=1e-8;
#define int long long 
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
int n;
struct node
{
    double x,y;
}a[maxn],b[maxn];
int sgn(double x)
{
    if(fabs(x)<eps) return 0;
    if(x<0) return -1;
    return 1;
}
node rotate(node now,double angle)
{
    node res;
    double cosa=cos(angle),sina=sin(angle);
    res.x=now.x*cosa-now.y*sina;
    res.y=now.x*sina+now.y*cosa;
    return res;
}
signed main ()
{
    cin>>n;
    double acorex=0,acorey=0;
    double bcorex=0,bcorey=0;
    for (int i=1;i<=n;i++)
    {
        cin>>a[i].x>>a[i].y;
        acorex+=a[i].x;
        acorey+=a[i].y;
    }
    acorex/=n;
    acorey/=n;
    for (int i=1;i<=n;i++)
    {
        cin>>b[i].x>>b[i].y;
        bcorex+=b[i].x;
        bcorey+=b[i].y;
    }
    bcorex/=n;
    bcorey/=n;
    for (int i=1;i<=n;i++)
    {
        a[i].x-=acorex;
        a[i].y-=acorey;
        b[i].x-=bcorex;
        b[i].y-=bcorey;
    }
    for (int i=1;i<=n;i++)
    {
        if(sgn(a[i].x)&&sgn(a[i].y))
        {
            swap(a[i],a[1]);
            break;
        }
    }
    for (int i=1;i<=n;i++)
    {
        double angle=atan2(a[1].y,a[1].x)-atan2(b[i].y,b[i].x);
        bool yes=true;
        for (int j=1;j<=n;j++)
        {
            bool find=false;
            node tmp=rotate(b[j],angle);
            for (int k=1;k<=n;k++)
            {
                if(sgn(a[k].x-tmp.x)==0&&sgn(a[k].y-tmp.y)==0)
                {
                    find=true;
                    break;
                }
            }
            if(!find) 
            {
                yes=false;
                break;
            }
        }
        if(yes)
        {
            cout<<"Yes\n";
            system ("pause");
            return 0;
        }
    }
    cout<<"No\n";
    system ("pause");
    return 0;
}

E(dp,同余)

E

这个题的大意是有n个数,我们需要把这个数组分成k段,每一段的和为bI,并且bi,问有多少个划分方式可以划分完这n个数

我们可以预先求出前缀和

对于前一段已经存在了j1个,此时的位置为i

只要(sum[i]sum[last]),即可满足条件

对于(sum[i]sum[last]),我们也可以知道这代表着sum[i]sum[last]是同余的

所以我们把同余的组合都放在一起

故可得出状态转移方程为

dp[i][j];//分配了i个数,分成j份
s[i][j];//分成j份,%j=i的数量
s[0][1]=1;//初状态,一个,余1=0,,只有这一个状态
for (int i=1;i<=n;i++)
{
    for (int j=1;j<=i;j++)
    {
        dp[i][j]=s[sum[i]%j][j];//把sum[x]%cnt看成一类,相同的余数(同余)
    }
    for (int j=1;j<=i+1;j++)
    {
        s[sum[i]%j][j]=s[sum[i]%j]+dp[i][j-1];//我们还需要更新同余的前缀
    }
}

知道状态转移方程就很好办了(我感觉这个我很难想到)

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include<cmath>
#include <bitset>
#include <unordered_map>
using namespace std;
const int maxn=3000+10;
const double eps=1e-8;
const int mod=1e9+7;
#define int long long 
#define ios  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
int n;
int sum[maxn];
int s[maxn][maxn],dp[maxn][maxn];
signed main ()
{
    cin>>n;
    for (int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        sum[i]=sum[i-1]+x;
    }
    s[0][1]=1;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=i;j++)
        {
             dp[i][j]=s[sum[i]%j][j]%mod;
        }
        for (int j=1;j<=i+1;j++)
        {
            s[sum[i]%j][j]=(s[sum[i]%j][j]+dp[i][j-1])%mod;
        }
    }
    int ans=0;
    for (int i=1;i<=n;i++)
    {
        ans=(ans+dp[n][i])%mod;
    }
    cout<<ans<<"\n";
    system ("pause");
    return 0;
}
posted @   righting  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示