天天看點

0704暑假集訓前的歡樂大雜燴總結

0704暑假集訓前的歡樂大雜燴總結

在TM迎接暑假超級無敵20天happy樂的前夕來了一場巨多人的超級爽的歡樂賽

然而老劉的資料翻車了 (是以我們在這裡就暫且不去論第5題)

T1 --質因數分解

【正解】:我都不想說什麼,爆0是最騷的。這麼睿智的一道題我居然GG了,平時的闆子要去多多複習啊。(話說我自己還寫過相應的部落格啪啪 )

重點:

被分解的數在long long範圍内

這題後來訂正的時候,枚舉質因子時我是

for(int j=2;j*j<=p;j++)
 .....
           

但是這樣會爆j的int範圍導緻失去部分分數。

是以我們得注意定義一個int級的變量時,如果有乘法要麼将變量還是改成ll,或者在乘法前加上(1LL)* 或者前面加上(long long)

【注意不是加在後面,不然前面已經炸了再加上就沒什麼意義了,我的T6最後一個點就是因為加在後面然後GG了】

T2—蛇形方陣2

【正解】每一圈k的起點必定是(k,k),然後再按順時針逆時針去模拟就可以了,比較水。

T3—大采購

【正解】多重背包闆子,注意二進制拆分操作。

(好吧,現在已經是單調隊列了,誰還用二進制拆分?)

T4—吉波 雞脖 那切數列

【問題描述】

有⼀個很著名的數列叫做斐波那契數列,它的定義式是

Fn = Fn−1 + Fn−2

其中,遞推的初始值為:F0 = 1, F1 = 1

在吉波那契數列這個問題中,我們相似地定義了⼀個吉波那契數列 Gn:

Gn = Gn−1 + Gn−2

對任何情況⽽⾔,G0 = 1, ⽽ G1 是⼀個随機的正整數 t。

現在告訴你 Gi 的值和兩個正整數 i, j,請你求出 Gj。鑒于 Gj 可能很⼤,

請你輸出 Gj mod 19960515。

【輸入格式】

輸⼊⽂件名為 gibonacci.in

有多組測試資料。第⼀⾏是⼀個正整數 T,表示測試資料的組數。

接下來 T ⾏,每⾏為⼀組測試資料,每組測試資料包含 3 個正整數 i, Gi

, j。

【輸出格式】

輸出⽂件名為 gibonacci.out

對于每組資料,輸出 Gj mod 19960515。

假如沒有合适的 t,請輸出 −1。

【樣例輸入】

2

1 1 2

3 5 4

【樣例輸出】

2

8

【資料規模與約定】

對于 30% 的資料,每個 Gibonacci 數列的 G1 = t ≤ 50

對于 50% 的資料,有 T ≤ 30

對于 100% 的資料,有 T ≤ 10000, 1 ≤ i, j ≤ 100000, 0 ≤ Gi < 19960515

不妨設G1=x

則序列可變為:1,x,x+1,2x+1,3x+2,5x+3,8x+5…

發現x的系數滿足斐波那契數列,常數項也滿足斐波那切數列,那麼已知Gi便可以知道它的x系數和常數項,看看x能否得出是正整數即可。

然後以此得出Gj的x系數和常數項然後就OK

别忘了取模%%%

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int q=19960515;
int f[100010],t;
int main()
{
	freopen("gibonacci.in","r",stdin);
	freopen("gibonacci.out","w",stdout);
   scanf("%d",&t);
   f[0]=0;
   f[1]=f[2]=1;
   for(int i=3;i<=100000;i++)
     f[i]=(f[i-1]+f[i-2])%q;
   while(t--)
   {
   	int x,y,c,w;
   	ll num;
	scanf("%d%lld%d",&x,&num,&y);
    c=f[x-1];
	w=f[x];
	if((num-c)%w||num-c<0) printf("-1\n");
	else 
	{
		int g=((num-c)/w)%q;
		printf("%lld\n",(((1LL)*f[y]*g)%q+f[y-1])%q);
	} 
   }
   return 0;
}

           

T5—魔塔

由于這道題老劉翻車了,利用記憶化搜尋dfs會有漏洞,而正解是什麼IDA*加堆優化,于是我暫且先不去談%%%(其實是我不會 )

老劉别打我

0704暑假集訓前的歡樂大雜燴總結

T6—對戰

【題面】

對戰

(inhouse.cpp/c/pas)

【問題描述】

在⼀條街道上有 n 個⼈,他們都喜歡打乒乓球。任意兩個⼈的家的位置都

不相同,按順序标為 1, 2, · · · , n。每個⼈都有⼀定的⽔平,用兩兩不等的整數表

示。

當兩個⼈想打球的時候,會找另⼀個⼈作為裁判,并到裁判家裡進⾏⼀場

較量。出于某種原因,他們希望裁判的⽔平介于兩⼈之間;同時,他們希望兩個

⼈到裁判家的總路程不超過兩個⼈的家的距離。

對于兩場較量,如果打球的兩個⼈不完全相同或者裁判不同,我們就認為

這兩場較量不同。求不同的較量的總數。

【輸入格式】

輸⼊⽂件名為 inhouse.in

輸⼊包含多組資料

輸⼊的第⼀⾏是⼀個整數 T,表示資料組數;

每組資料占⼀⾏,包含 n + 1 個整數:n, a1, a2, · · · , an。其中 a1, a2, · · · , an

表示家位于相應位置的⼈的⽔平。

【輸出格式】

輸出⽂件名為 inhouse.out

對每組資料,用⼀⾏輸出⼀個整數,表示不同的較量的總數。

【樣例輸入】

1

3 1 2 3

【樣例輸出】

1

【資料規模與約定】

對于 40% 的資料,有 n ≤ 1000;

對于所有資料,有 T ≤ 20, 3 ≤ n ≤ 100000,每個⼈的⽔平都是不超過200000 的正整數。

【正解】一開始看到題想到使用雙指針指向兩個互相對決的人,然後累加他們之間合法的裁判,發現這樣就十分暴力,時間複雜度高。

正難則反的思想:枚舉2~n-1個人去做裁判,看看能給多少組人去當裁判即可。

明顯隻需知道裁判i左邊比他高的L1[i],右邊比他低的R1[i],左邊比他矮的L2[i],右邊比他高的R2[i]

答案就是SUM(L1[i]*R2[i]+L2[I]*R1[i]) 2<=i<=n-1

那麼現在的問題就是如何快速得到這個L1,R1,L2,R2;

用樹狀數組維護這種關系,類似逆序對的求法,隻需要減一減就OK了。

code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,maxx=-1;
ll a[100501],c[200101];
ll lef1[105001],righ1[100501],lef2[100501],righ2[100501];;

void add(ll x,ll val)
{
	for(;x<=maxx;x+=x&-x)
	  c[x]+=val;
}

ll sum(int x)
{
	ll ans=0;
	for(;x;x-=x&-x)
	  ans+=c[x];
	return ans;
}
int main()
{
	freopen("inhouse.in","r",stdin);
	freopen("inhouse.out","w",stdout);
  scanf("%d",&t);
  while(t--)
  { int n;
  	scanf("%lld",&n);
  	ll ans=0;
	maxx=-1;
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),maxx=max(a[i],maxx);
  	for(ll i=1;i<=n;i++)
   {
   	lef1[i]=sum(a[i]-1); 
    lef2[i]=lef1[i];//左邊比他低
   	lef1[i]=i-1-lef1[i];	//左邊比他高
	add(a[i],1);
   }
   memset(c,0,sizeof(c));
   for(ll i=n;i>=1;i--)
   {
   	righ1[i]=sum(a[i]-1);
   	righ2[i]=righ1[i];//右邊比他低
   	righ1[i]=n-i-righ1[i];//右邊比他高
	add(a[i],1);
   }
   for(ll i=2;i<n;i++)
     ans+=(ll)(lef1[i]*righ2[i]),ans+=(ll)(lef2[i]*righ1[i]);//注意這(ll)
   printf("%lld\n",ans);
   memset(c,0,sizeof(c));
  }
}
           

前面已經提過,你原本以為的int不會爆,但是相乘就可能會GG,是以保險起見還是加上一個(ll)或者

1LL*;不過要加在乘法運算的前面

總結:因為爆int失分高達30,因為闆子忘記敲失分100分。細節處理失分10分。然後魔塔就不說了,直接GG了。這啟示我,int乘法加(ll)是必須的,闆子多去敲敲,不複習就真的GG,功在平時;

細節處理也很重要,思路要更缜密一些。

Summer Holiday Training,I’m Coming !

繼續閱讀