首页 > 其他分享 >AtCoder Beginner Contest 207(D,E)

AtCoder Beginner Contest 207(D,E)

时间:2023-04-11 18:44:06浏览次数:40  
标签:AtCoder const 207 Beginner int double sum maxn include

AtCoder Beginner Contest 207(D,E)

D(计算几何)

D

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

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

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

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

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

对于求重心\(corex\)和\(corey\),是每一个点的\(x\)和\(y\)的平均值

然后以\(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\times sin(angle)-y\times cos(angle)\)

\(ty=y\times cos(angle)+y\times 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\)段,每一段的和为\(b_I\),并且\(b_i%i=0\),问有多少个划分方式可以划分完这\(n\)个数

我们可以预先求出前缀和

对于前一段已经存在了\(j-1\)个,此时的位置为\(i\)

只要\((sum[i]-sum[last])%j=0\),即可满足条件

对于\((sum[i]-sum[last])%j=0\),我们也可以知道这代表着\(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;
}

标签:AtCoder,const,207,Beginner,int,double,sum,maxn,include
From: https://www.cnblogs.com/righting/p/17307281.html

相关文章

  • AtCoder Beginner Contest 247(E,F)
    AtCoderBeginnerContest247(E,F)E(思维)E这个题大意就是给一个长度为\(n\)的数组,一个\(x\)和一个\(y\),问这个数组里面可以找到多少段\([l,r]\)满足这一段里面的最大值是\(x\),最小值是\(y\)这里的做法是固定最右端,寻找最左端的可能的数量,最后相加对于每一个位置,都有作为最......
  • AtCoder Regular Contest 127
    D-LIS2难搞的地方在于取min,考虑比较\((a_i\oplusa_j,b_i\oplusb_j)\)两者的过程:是在它们第一位不一样的地方比较,取该位为0的那个。而判断两个数在某位是否相等,可以想到异或操作,然后把这两者异或起来后,由异或运算的交换律可得等价于\((a_i\oplusb_i)\oplus(a_j\oplus......
  • AtCoder Regular Contest 159
    Preface这周六紧张刺激的一日三赛,上午蓝桥杯,晚上ARC之后隔5min就是CF,可谓是手搓键盘到冒烟的一天了这场其实打的感觉很没水准,B刚开始没想清楚很多边界条件挂了三发,45min左右才过然后C的构造也不太会,随便写了个暴力也是挂挂挂,只好弃了去写D题了结果发现D题好像是个不难的线段树......
  • 练习记录- AtCoder Beginner Contest 295(D)
    vp的觉得我的D很聪明所以来写一下(乐D-ThreeDaysAgo题意就是求所有字符出现次数均为偶数的字串数量太笨了所以想了很久我把存在奇数个1当作第2位是2那么当经过了两次1 2^2这个2就变成了02就是第二位就是4...以此类推 所以我遍历一遍字符串求出当前的异或......
  • 练习记录-AtCoder Beginner Contest 296(A-F)
    vp的感觉整场挺智慧A-Alternately找有没有连续的男女#include<bits/stdc++.h>#defineclosestd::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)usingnamespacestd;typedeflonglongll;constllMAXN=3e5+7;constllmod=1e9+7;constllinf=0x3......
  • AtCoder Beginner Contest 278
    口胡一下,从青色开始E-GridFilling给定一个W×H的矩阵,每个格子有一个数,在1和N之间,给定w<=W,h<=H,对于每个满足1<=i<=W-w+1,1<=j<=H-h+1的格子(i,j),求以它为左上角的w×h矩阵被遮住后整个大矩阵还剩下几种数字。W,H,N,w,h<=300首先我们看见这个熟悉的300就知道是立方算法又注......
  • AtCoder ABC286 C - Chinese Restaurant
    AtCoderABC286C-ChineseRestaurant题目描述有\(N\)个人从\(0\)开始编号,按逆时针顺序间隔均匀地坐在转盘周围。在开始时,第\(p_i\)盘菜在第\(i\)个人的前面。现在,你可以进行以下操作\(0\)次或多次。将转盘逆时针旋转\(\dfrac{1}{N}\)圈。也就是说,旋转前......
  • AtCoder ABC295 D - Three Days Ago
    AtCoderABC295D-ThreeDaysAgo题目描述给出一个数字串,问有多少子段满足,可以以某种方式将这个子段重排,将子段分成两个完全相同的部分。样例输入输出202303224\((1,6)(1,8)(2,7)(7,8)\)都可以满足条件分析如果要满足某一个字段可以被分为两个相同的部分,则不......
  • AtCoder ABC294 F - Sugar Water 2
    AtCoderABC294F-SugarWater2题意有\(2\)排糖和水。第\(1\)排有\(N\)瓶糖和\(N\)瓶水。糖分别有\(A_i\)克,水分别有\(B_i\)克。第\(2\)排有\(M\)瓶糖和\(M\)瓶水,糖分别有\(C_i\)克,水分别有\(D_i\)克。若要从第\(1\)排糖水中找到\(A_i\)克糖和......
  • AtCoder Beginner Contest 226(E,F,G)
    AtCoderBeginnerContest226(E,F,G)E(并查集)E这个题的大意是给我们一个无向图,我们可以把这些无向边变成有向边,让每一个点的入度都是\(1\),问有多少种变化方式要让有\(x\)个点的无向图,形成一棵树的边的数量是\(x-1\),但是我们需要的是每一个点的入度为\(1\),那么我们只还需要一条......