PDA

View Full Version : GCD برای n عدد



sa1378
پنج شنبه 29 آبان 1393, 08:43 صبح
سلام
سوال:
دنباله اعداد از x1 تا x2 داریم
و یکی دیگه هم از y1 تا y2
میخوایم ببینیم چندتا زوج به صورت (X,Y) داریم که Y بین y1,y2 باشه و X بین x1,x2 باشه
و ب.م.م X و Y برابر 1 بشه
از اونجایی که طول دنباله حداکثر 6^10 هست و حداکثر زمان هم 5 ثانیه هست نمیتونیم به ازای هر دوتایی ب.م.م رو حساب کنیم
چه ایده ای باید بزنیم؟

مسعود اقدسی فام
جمعه 30 آبان 1393, 00:56 صبح
هنوز فرصت نشده فکر کنم در موردش. اما به نظرم بهتره همچین سوالاتی رو که مربوط به طراحی الگوریتم هست اینجا مطرح کنید:


http://barnamenevis.org/forumdisplay.php?40-%D8%A7%D9%84%DA%AF%D9%88%D8%B1%DB%8C%D8%AA%D9%85%D 8%8C-%DA%A9%D8%A7%D9%85%D9%BE%D8%A7%DB%8C%D9%84%D8%B1%D 8%8C-%D9%87%D9%88%D8%B4-%D9%85%D8%B5%D9%86%D9%88%D8%B9%DB%8C-%D9%88-%D8%B3%D8%A7%D8%AE%D8%AA%D9%85%D8%A7%D9%86-%D8%AF%D8%A7%D8%AF%D9%87-%D9%87%D8%A7

sa1378
جمعه 30 آبان 1393, 09:20 صبح
سوال دقیقش رو هم خواستین اینجاست (https://sharecode.io/contests/problem/61839729/E)

rahnema1
جمعه 30 آبان 1393, 10:54 صبح
فرض کنید gcd برابر 3 باشه
اولین عنصر لیست x را می کشیم بیرون و به عناصر اول تجزیه می کنیم
مثلا میشه 2 3 5 7
تابع T هم تعداد عناصری از لیست y را میده که به پارامتر تابع T بخشپذیر باشند که خیلی راحت با یک جمع و ضرب به دست میاد
باید T ها بزرگتر و مساوی 3 بدست بیاد
سپس T ها را اینجور با هم جمع می کنیم
T(3)-T(3*5)-T(3*7)+T(3*5*7) = T(3)-T(15)-(21)+T(105)
این برای عنصر اول، برای عناصر بعدی x هم همینطور ادامه می دهیم

omid_kma
جمعه 30 آبان 1393, 11:10 صبح
اول بازه ها رو به d تقسیم کن این طوری فقط کافیه اعدادی که نسبت به هم اول هستن رو پیدا کنی
برای هر x تمام عامل های اول رو حساب کن (چون n تا تست کیس هست باید ذخیره هم بشن )
با استفاده از این رابطه (http://en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle)http://upload.wikimedia.org/math/0/7/1/0719353c1c4a12748b1f2efb85a49255.png
تمام زیر مجموعه های شامل 1 عضو اول 2 عضو اول و ... رو بسازو اونای که در بازه y هستن رو نگه دار .
تعداد میشه سایز کل حالت ها - سایز مجموعه های 1 عضوی +سایز مجموعه های 2 عضوی - سایز مجموعه های 3 عضوی و ...

sa1378
جمعه 30 آبان 1393, 11:26 صبح
فرض کنید gcd برابر 3 باشه
اولین عنصر لیست x را می کشیم بیرون و به عناصر اول تجزیه می کنیم
مثلا میشه 2 3 5 7
تابع T هم تعداد عناصری از لیست y را میده که به پارامتر تابع T بخشپذیر باشند که خیلی راحت با یک جمع و ضرب به دست میاد
باید T ها بزرگتر و مساوی 3 بدست بیاد
سپس T ها را اینجور با هم جمع می کنیم
T(3)-T(3*5)-T(3*7)+T(3*5*7) = T(3)-T(15)-(21)+T(105)
این برای عنصر اول، برای عناصر بعدی x هم همینطور ادامه می دهیم


اول بازه ها رو به d تقسیم کن این طوری فقط کافیه اعدادی که نسبت به هم اول هستن رو پیدا کنی
برای هر x تمام عامل های اول رو حساب کن (چون n تا تست کیس هست باید ذخیره هم بشن )
با استفاده از این رابطه (http://en.wikipedia.org/wiki/Inclusion%E2%80%93exclusion_principle)http://upload.wikimedia.org/math/0/7/1/0719353c1c4a12748b1f2efb85a49255.png
تمام زیر مجموعه های شامل 1 عضو اول 2 عضو اول و ... رو بسازو اونای که در بازه y هستن رو نگه دار .
تعداد میشه سایز کل حالت ها - سایز مجموعه های 1 عضوی +سایز مجموعه های 2 عضوی - سایز مجموعه های 3 عضوی و ...
از هردوتون ممنون
من راه حل آقای rahnema1 رو رفتم چون ساده تر بود یکم
ولی الان نمیدونم چجوری باید تابع calc رو توی کدم پیاده سازی کنم
(calc همون قسمتی هست که باید اینو حساب میکرد):
T(3)-T(3*5)-T(3*7)+T(3*5*7) = T(3)-T(15)-(21)+T(105)
کدی هم که زدم اینه:
#include <iostream>
#include <vector>
using namespace std;
int x1,x2,y1,y2,d,memT[1000*1000],ans;
bool mark[1000*1000];
vector <int> div;

void tajzie(int x)
{
for(int i=2;i*i<=x;i++)
{
while(x%i==0)
{
div.push_back(i);
x/=i;
}
}
if(x!=1)
div.push_back(x);
}

int T(int x)
{
int p=0;
if(mark[x]==true)
return memT[x];
mark[x]=true;
for(int i=y1;i<=y2;i++)
if(i%x==0)
p++;
return p;
}

int calc()
{
int end=div.size();

}

int main() {
int t;
cin>>t
for(int i=0;i<t;i++)
{
cin>>x1>>x2>>y1>>y2>>d;
for(int j=x1;j<=x2;j++)
{
if(j%d==0)
{
tajzie(j/d);
ans+=calc();
div.erase();
}
}
cout<<ans<<endl;
}

return 0;
}

rahnema1
جمعه 30 آبان 1393, 12:39 عصر
تابع T لازم نبود داخلش حلقه بذارید گفتم با یک تفریق و تقسیم ساده تعداد مورد نظر به دست میاد
مثلا فرض کنید y1 برابر 17 و y2 برابر 37 باشه و بخواهیم تعداد اعدادی که بر 3 بخشپذیره پیدا کنیم
تعداد برابر میشه با(36-18+3)/3
علامت مثبت و منفی T هم همون طور که omid_kma اشاره کردند از wikipedia مطالعه کنید

sa1378
جمعه 30 آبان 1393, 13:05 عصر
تابع T لازم نبود داخلش حلقه بذارید گفتم با یک تفریق و تقسیم ساده تعداد مورد نظر به دست میاد
مثلا فرض کنید y1 برابر 17 و y2 برابر 37 باشه و بخواهیم تعداد اعدادی که بر 3 بخشپذیره پیدا کنیم
تعداد برابر میشه با(36-18+3)/3
علامت مثبت و منفی T هم همون طور که omid_kma اشاره کردند از wikipedia مطالعه کنید

اصل شمول و عدم شمول رو بلدم
چجوری همه زیرمجموعه های 1 عضوی،2 عضوی و... رو دخیره کنم و استفاده کنم ازشون؟

rahnema1
جمعه 30 آبان 1393, 13:14 عصر
اصل شمول و عدم شمول رو بلدم
چجوری همه زیرمجموعه های 1 عضوی،2 عضوی و... رو دخیره کنم و استفاده کنم ازشون؟

چرا همه زیرمجموعه ها را پیدا کنید؟ فکر نکنم لازم باشه

sa1378
جمعه 30 آبان 1393, 13:44 عصر
چرا همه زیرمجموعه ها را پیدا کنید؟ فکر نکنم لازم باشه

خب منم منظورم اینه چیکار کنیم دیگه...
الان میخوام یه کد بزنم که یه d بگیره با یه وکتور که بقیه عوامل عدد هستن
بعد بیاد براشون حساب کنه

rahnema1
جمعه 30 آبان 1393, 13:58 عصر
خب من که گفتم به شما
اصلا لازم نیست هیچ زیر مجموعه ای حساب بشه
فقط برای هر x مجموع تابعهای T را حساب کنید و با هم جمع کنید. همین

sa1378
جمعه 30 آبان 1393, 16:00 عصر
خب من که گفتم به شما
اصلا لازم نیست هیچ زیر مجموعه ای حساب بشه
فقط برای هر x مجموع تابعهای T را حساب کنید و با هم جمع کنید. همین

الان مثلا حاصل تجزیه شد 2و2و5و7و13
چجوری تابع رو بنویسم که T هارو جمع کنه؟
مثلا برای 3و5و7 که خودتون گفتین میشد این:
T(3)-T(3*5)-T(3*7)+T(3*5*7) = T(3)-T(15)-(21)+T(105)

rahnema1
جمعه 30 آبان 1393, 20:44 عصر
مثلا اگه 2 2 3 5 7 13 باشه و gcd برابر 3 مد نظر باشه این ترکیبات به وجود میاد

+{3}
-{3 2}
-{3 5}
-{3 7}
-{3 13}
+{3 2 2} <<=
+{3 2 5}
....
....

اون موردی که دو بار 2 تکرار شده بی معنی هست و نباید به حساب بیاد

sa1378
شنبه 01 آذر 1393, 14:19 عصر
مثلا اگه 2 2 3 5 7 13 باشه و gcd برابر 3 مد نظر باشه این ترکیبات به وجود میاد

+{3}
-{3 2}
-{3 5}
-{3 7}
-{3 13}
+{3 2 2} <<=
+{3 2 5}
....
....

اون موردی که دو بار 2 تکرار شده بی معنی هست و نباید به حساب بیاد
این رو فهمیدم
چجوری کدی بزنیم که تمام اینایی که نوشتین رو بدست بیاره؟
باید حبقه گذاشت یا مثلا بازگشتی؟؟

rahnema1
شنبه 01 آذر 1393, 17:59 عصر
با روشهای مختلف میشه نوشت. فکر کنم توی یک تاپیک khoshghalb هم روش بازگشتی را برای شما نوشتند یا تاپیکهای دیگه این هم یه روش دیگه

#include <bitset>
#include <cmath>
#include <iostream>
using namespace std;
int main()
{
const int size =4;
int arr[size] = {2 ,5 ,7 ,13};
for(int i=0;i < pow(2,size); i++)
{
cout<<3<<",";
auto a = bitset <size>(i);
for(int j = 0; j < size;j++)
{
if(a[j]) cout<<arr[j]<<",";
}
cout<<"\n";
}
}