[数论] 小球碰撞


题目描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

输入

在这里插入图片描述

输出

在这里插入图片描述

样例输入

2 3 1

样例输出

2.5


解题思路

为了方便,我们把 m a ma ma记作 a a a,把 m b mb mb记作 b b b,把 P P P记作 c c c,那么题目就变成了:
已知 a , b , c a,b,c a,b,c,求 a x + b y = c ax+by=c ax+by=c的一组解,使得 0.5 ∗ a ∗ x 2 + 0.5 ∗ b ∗ y 2 0.5*a*x^2+0.5*b*y^2 0.5ax2+0.5by2最小,输出这个最小值
显然,第一步我们用拓展欧几里得算法求出这个不定方程的一组特解,为 { x 0 y 0 \begin{cases}x_0 \\ y_0 \\ \end{cases} {x0y0,令 a a a b b b的最大公因数为 d d d,那么通解为 { x 1 = x 0 + b d t y 1 = y 0 − a d t \begin{cases}x_1=x_0+\frac{b}{d}t \\ y_1=y_0-\frac{a}{d}t\\ \end{cases} {x1=x0+dbty1=y0dat
所以 a n s = 0.5 ( a x 1 2 + b y 1 2 ) ans=0.5(ax_1^2+by_1^2) ans=0.5(ax12+by12) x 1 = x 0 + b d t x_1=x_0+\frac{b}{d}t x1=x0+dbt y 1 = y 0 − a d t y_1=y_0-\frac{a}{d}t y1=y0dat代入这个式子化简后可得: a n s = 0.5 ( a + b d 2 a b t 2 + 2 a b ( x 0 − y 0 ) d t + a x 0 2 + b y 0 2 ) ans=0.5(\frac{a+b}{d^2}abt^2+2\frac{ab(x_0-y_0)}{d}t+ax_0^2+by_0^2) ans=0.5(d2a+babt2+2dab(x0y0)t+ax02+by02)
这就是一个关于 t t t的二次函数,对称轴为: t 1 = − a b ( x 0 − y 0 ) d a + b d 2 a b = ( y 0 − x 0 ) d a + b t_1=-\frac{\frac{ab(x_0-y_0)}{d}}{\frac{a+b}{d^2}ab}=\frac{(y_0-x_0)d}{a+b} t1=d2a+babdab(x0y0)=a+b(y0x0)d
再在 t 1 t_1 t1两边的两个整点(也就是 ⌊ t 1 ⌋ \lfloor t1 \rfloor t1 ⌊ t 1 ⌋ + 1 \lfloor t1 \rfloor+1 t1+1)中去找答案即可


参考代码

#include <cstdio>
#include <cstring>
#include <cmath>
#define reg register
 
template <class T>
inline T read() {
    T x = 0; T f = 1; char s = getchar();
    while(s < '0' || s > '9') {if(s == '-') f = -1; s = getchar();}
    while(s >= '0' && s <= '9') {x = (x << 3) + (x << 1) + s - 48; s = getchar();}
    return x * f;
}
 
template <typename T>
inline void wri(T x) {
    if(x < 0) {x = -x; putchar('-');}
    if(x / 10) wri(x / 10);
    putchar(x % 10 + 48);
}
 
template <typename T>
inline void write(T x, char s) {
    wri(x);
    putchar(s);
}
 
template <typename T>
inline T Min(T x, T y) {return x < y ? x : y;}
 
#define LL long long
 
int ma, mb, p, gcd;
double va, vb, t, tmp, pa, pb, ans;
 
inline int exgcd(int a, int b, double &x, double &y) {	//拓展欧几里得算法
    if(! b) {
        x = 1, y = 0;
        return a;
    }
    else {
        int tmp = exgcd(b, a % b, y, x);
        y -= x * (a / b);
        return tmp;
    }
}
 
int main() {
    ma = read<int>(), mb = read<int>(), p = read<int>();
    gcd = exgcd(ma, mb, va, vb);
    va *= (p * 1.0 / gcd), vb *= (p * 1.0 / gcd);	//算出特解
    if(p % gcd != 0) {	//判断无解
        puts("-1");
        return 0;
    }
    t = (vb - va) * gcd * 1.0 / (ma + mb);	//算出t1并在两边找答案
    tmp = floor(t);
    pa = va + tmp * (mb / gcd);
    pb = vb - tmp * (ma / gcd);
    ans = 0.5 * ma * pa * pa + 0.5 * mb * pb * pb;
    tmp = floor(t) + 1;
    pa = va + tmp * (mb / gcd);
    pb = vb - tmp * (ma / gcd);
    ans = Min(ans, 0.5 * ma * pa * pa + 0.5 * mb * pb * pb);
    LL q = ans;	//判断是否为浮点数
    if(ans != q)
        printf("%.1lf\n", ans);
    else
        write(q, '\n');
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
各个小球在一起碰撞实例··· // FallDlg.cpp : implementation file // #include "stdafx.h" #include "Fall.h" #include "FallDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CAboutDlg dialog used for App About class CAboutDlg : public CDialog { public: CAboutDlg(); // Dialog Data //{{AFX_DATA(CAboutDlg) enum { IDD = IDD_ABOUTBOX }; //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP() }; CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) //{{AFX_MSG_MAP(CAboutDlg) // No message handlers //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFallDlg dialog CFallDlg::CFallDlg(CWnd* pParent /*=NULL*/) : CDialog(CFallDlg::IDD, pParent) { //{{AFX_DATA_INIT(CFallDlg) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT // Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CFallDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CFallDlg) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CFallDlg, CDialog) //{{AFX_MSG_MAP(CFallDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFallDlg message handlers BOOL CFallDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here return TRUE; // return TRUE unless you set the focus to a control } void CFallDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CFallDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this to obtain the cursor to display while the user drags // the minimized window. HCURSOR CFallDlg::OnQueryDragIcon() { return (HCURSOR) m_hIcon; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值