1. 程式人生 > >[jzoj]2018.07.11【NOIP普及組】模擬賽D組:解題報告

[jzoj]2018.07.11【NOIP普及組】模擬賽D組:解題報告

目錄

1.和諧數

2.分數

3.終極數

4.串

1.和諧數

給定一個長度為N的序列a,對於每一個數都可選或不選,把選出的數有序組成一個新的序列b,使b序列的“和諧數”最大。一個序列的和諧數如下定義:對於位置i,如果第奇數次選的則加上bi,偶數次選的則減去bi 
注意:新的序列b必須是從左到右依次在a序列選擇的,即不能打亂順序。

資料範圍:

    對於20%的資料,1<=n<=20 

    對於50%的資料,1<=n<=1000 
    對於100%的資料,1<=n<=10000000,1<=Ai<=100

輸入:輸入的第一行是一個n,第二行為n個數,即序列a

輸出:輸出一行一個整數,即表示最大的和諧數

思路:

DP: 
第一想法當然是暴力,不過這資料告訴我們暴力的期望分應該最多隻有50分,然後我們發現可以用DP求解。 
因為從左往右依次選而且可選可不選,所以設 
f[i][1]表示到第i步為選擇為偶數次時和諧數最大是多少. 
f[i][2]表示到第i步為選擇為奇數次時和諧數最大是多少. 
然後推出狀態轉移方程: 
f[i][1] = max(f[i - 1][1],f[i - 1][2] - a[i]); 
f[i][2] = max(f[i - 1][2],f[i - 1][1] + a[i]); 

#include<functional>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<cmath>
int f[2][3];
int maxn(int a,int b){return a > b ? a : b;}
inline int read()
{
    int ret = 0; 
	int w = 0; 
	char ch = 0;
    while(!isdigit(ch)) 
	{
		w |= ch == '-';
		ch = getchar();
	}
    while(isdigit(ch)) 
		ret = (ret << 3) + (ret << 1) + (ch ^ 48),ch = getchar();
    return w ? -ret : ret;
}
inline void write(int x)
{
     if(x < 0) 
	 	putchar('-'),x = -x;
     if(x > 9) 
	 	write(x / 10);
     putchar(x % 10 + '0');
}
int main()
{
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	int n,x;
	n = read();
	for(int i = 1;i <= n;i++)
	{
		x = read();
		f[i % 2][1] = maxn(f[(i + 1) % 2][1],f[(i + 1) % 2][2] - x);
		f[i % 2][2] = maxn(f[(i + 1) % 2][2],f[(i + 1) % 2][1] + x);
	}
	write(maxn(f[n % 2][1],f[n % 2][2]));
	return 0;
}

2.分數

題目: 

求n1個a[i]的乘積跟n2個b[i]乘積的既約分數,(既約分數就是分子分母最大公約數為1的分數)。

對於20%的資料,n1,n2<=10,Ai,Bi<=10 
對於60%的資料,n1,n2<=1000,Ai,Bi<=1000 
對於100%的資料,n1,n2<=100000,Ai,Bi<=10000 
資料保證不會出現分數的值為0的情況

思路:

20分的就是直接得到乘積後直接用輾轉相除法約去最大公因數即可 
時間複雜度:O(n) 
60分就使用高精度,把兩個序列兩兩去除公因數 
AC的話: 
因為Ai,Bi<=10000,所以可以先塞素數,然後對其分解質因數,把合數化成質數(質數則不變),然後2個序列a,b都這樣做,最後用兩個序列的分解出來的數相互抵消,類似於去重。 
然後將2個序列剩下的數分別用高精度算出乘積,然後直接輸出 
PS:抵消完後的序列乘積滿足既約分數。 
不過我們在高精度的時候要用到壓位,不然容易超時,即改變進位制,因為Ai,Bi<=10000,所以長整型最大壓位到200000左右… 
時間複雜度O(n*m) 

M為常數,不會超過100,因為10000以內我們只需分解到100即可,分解完後如果還大於1,則可證這一定是個質數

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<cmath>
#define maxn 100010
using namespace std;
int a[maxn],b[maxn],ans[maxn],rp[maxn];
bool p[maxn];
int kp[10010];
int la;
inline void gjd(int k)
{
	int j,x;
	x = 0;
	for(j = 1;j <= la;j++)
	{
		ans[j] = k * ans[j] + x;
		x = ans[j] / 100000;
		ans[j] %= 100000;
	}
	ans[la + 1] = x;
	la++;
	if(ans[la] == 0)
		la--;
}
string check(int p)
{
	string ret;
    if (p <= 9999) 
		ret += '0';
    if (p <= 999) 
		ret += '0';
    if (p <= 99)
		ret += '0';
    if (p <= 9)  
		ret += '0';
	return ret;
}
void doa(int k)
{
	a[kp[k]]++;
     if (k == kp[k])
	 	return ;
     doa(k / kp[k]);
}
void dob(int k)
{
	b[kp[k]]++;
     if (k == kp[k])
	 	return ;
     dob(k / kp[k]);
}
inline int read()
{
    int ret = 0; 
	int w = 0; 
	char ch = 0;
    while(!isdigit(ch)) 
	{
		w |= ch == '-';
		ch = getchar();
	}
    while(isdigit(ch)) 
		ret = (ret << 3) + (ret << 1) + (ch ^ 48),ch = getchar();
    return w ? -ret : ret;
}
int main()
{
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	int n,x,m,j,k;
	n = read();
	for (int i = 1;i <= n;i++)
	{
		x = read();
		a[x]++;
	}
	m = read();
	for (int i = 1;i <= m;i++)
	{
		x = read();
		b[x]++;
	}
	p[1] = true;
	kp[1] = 1;
	for (int i = 2;i <= 10000;i++)
	{
		if (p[i] == false)
		{
			j = 1;
			while (i * j <= 10000)
			{
				p[i * j] = true;
				if (kp[i * j] == 0)
					kp[i * j] = i;
				j++;
			}
		}
	}
	for (int i = 2;i <= 10000;i++)
	{
		k = a[i];
		a[i] = 0;
		for (int j = 1;j <= k;j++)
			doa(i);
		k = b[i];
		b[i] = 0;
		for (int j = 1;j <= k;j++)
			dob(i);
	}
	for (int i = 2;i <= 10000;i++)
	{
		if (a[i] >= b[i])
		{
			a[i] = a[i] - b[i];
			b[i] = 0;
		}
		else
		{
			b[i] = b[i] - a[i];
			a[i] = 0;
		}
	}
	ans[1] = 1;
	la = 1;
	for (int i = 2;i <= 10000;i++)
		for (int j = 1;j <= a[i];j++)
			gjd(i);
	cout << ans[la];
	ans[la] = 0;
	for (int i = la - 1;i >= 1;i--)
	{
		cout << check(ans[i]);
		cout << ans[i];
		ans[i] = 0;
	}
	la = 1;
	ans[1] = 1;
	for (int i = 2;i <= 10000;i++)
		for (int j = 1;j <= b[i];j++)
			gjd(i);
	cout << " ";
	if (ans[1] == 1 && la == 1){}
	else
	{
		cout << ans[la];
		for (int i = la - 1;i >= 1;i--)
		{
			cout << check(ans[i]);
			cout << ans[i];
		}
	}
}

3.終極數

題目: 

給定一個長度為n的序列a,試求出對於序列a的每一個字首的終極數x,使得 

最小,試求出終極數t(如若有多個終極數t,只需輸出最小的那個)

思路:

其實就是選中位數~ 

維護一個大根堆和一個小根堆,並且保證 1.小根堆節點個數大於等於大根堆節點個數。 2.小根堆的堆頂元素大於大根堆的堆頂元素。 這就說明有兩種特殊情況: 

(1)將要放進小根堆時,發現大根堆的堆頂元素大於當前要放進小根堆的元素。 

(2)將要放進大根堆時,發現小根堆的堆頂元素小於此元素。 設此元素為x。 

(1)情況:把 x 放到大根堆中,並且把大根堆的堆頂放到小根堆當中,並維護兩堆 性質。 

(2)情況:把 x 放到小根堆中,並且把小根堆的堆頂放到大根堆當中,並維護兩堆 性質。 

詳細見程式碼:t3題解

4.串

題目: 

給定一個0-1串,請找到一個儘可能長的子串,其中包含的0與1的個數相等。

30%的資料 串的長度<20 100%的資料 長度不超過1000000 

保證字串只出現0,1

思路:

當0和1的差值與上一個0和1的差值相同時,那麼他們之間的字串中0和1的數目是相同的。求出最大的就行了。舉個例子:前面0,1為a, b,後面0,1為aa, bb, a - b = aa - bb,  得 a - aa = b - bb;

t4題解

相關推薦

[jzoj]2018.07.11NOIP普及模擬D解題報告

目錄 1.和諧數 2.分數 3.終極數 4.串 1.和諧數 給定一個長度為N的序列a,對於每一個數都可選或不選,把選出的數有序組成一個新的序列b,使b序列的“和諧數”最大。一個序列的和諧數如下定義:對於位置i,如果第奇數次選的則加上bi,偶數次選的則減去bi  注

[jzoj]2018.07.12NOIP普及模擬D解題報告

1.權勢二進位制 題目: 一個十進位制整數被叫做權勢二進位制,當他的十進位制表示的時候只由0或1組成。例如0,1,101,110011都是權勢二進位制而2,12,900不是。 當給定一個n的時候,計算一下最少要多少個權勢二進位制相加才能得到n。 輸入: k組測試資料。 輸出:

[jzoj]2018.07.15NOIP普及模擬D解題報告

目錄: 1.馬農 2.馬語翻譯 3.馬球比賽  4.棋盤遊戲 1.馬農 題目描述: 在觀看完戰馬檢閱之後,來自大草原的兩兄弟決心成為超級“馬農”,專門飼養戰馬。 兄弟兩回到草原,將可以養馬的區域,分為 N*N 的單位面積的正方形, 並實地進行考察,歸納出了每

紀中訓練 day5 NOIP普及模擬D 解題報告

目錄 大意 從左到右,問加了一個’p’後一共有幾個noi?(p可以為n,o,i中的一個)長度小於100001 思路 加p之前,noi的個數為每個o之前n的個數*之後i的個數並累加。 加p之後,有三種情況:N,O,I N肯定是放在

2017.07.11NOIP提高模擬B

span 結果 數組 運算 重要 eight 一點 對數 理解 Summary   今天的比賽打得還不錯,第一題被同桌灌輸的貪心,純模擬洗腦了,然後steal的看了一下,發現怎麽也對不了,一直在檢查。最後10分鐘才找出反例,推出動態規劃方程,沒有想到怎麽轉移,比賽就結束了

[jzoj]2018.08.09NOIP提高模擬C:解題報告

目錄: 1.種類分配(Breed Assignment) 2.資訊傳遞(Message Relay) 3.計算周長(Perimeter) 4.找奶牛(Find the Cow!) 1.種類分配(Breed Assignment) 題目:

2018.10.06NOIP普及模擬C

T1 YY 題目描述 最近小h接到命令,要再出一份題目,於是小h馬上陷入了沉思之中,想到了yy曾經出過的一道題目:給出一個超大正整數S,S的位數小於500000,然後找出一個數 n, 使得n

2017.07.10NOIP提高模擬B

font mic 集合點 之間 現在 problem 決定 family 打破 Summary   今天題目總體不是難,但是分數很低,只有100+10+30,其中第二題還是以前做過的,第一題設計數論,而且以前做過同一個類型的題目,比賽推了很長時間。第三題時以前做過的原題,

2017.07.14NOIP提高模擬B

noi net 處理 contest 比賽 size 很大的 pan 每天 Summary   這次比賽因為遲到了,少了很多時間,也受到了相應的懲罰,這是好的,是個標記牌,警醒著我。這次比賽的題目很難,也就是說,大家的得分都很低,總的來說,收獲還是很大的,因為有非常多的技

2017.11.25NOIP提高模擬A

mes turn 我們 一個 線段樹 getc stdout 線段樹+離散化 提高 2017.11.25【NOIP提高組】模擬賽A組 T1 3467. 【NOIP2013模擬聯考7】最長上升子序列(lis) T2 3468. 【NOIP2013模擬聯考7】OSU!(osu)

2018.12.30NOIP提高模擬C總結

2018.12.30【NOIP提高組】模擬賽C組總結 今天成功迴歸開始做比賽 感覺十分良(zhōng)好(chà)。 統計數字(count.pas/c/cpp) 字串的展開(expand.pas/c/cpp) 矩陣取數遊戲(game.pas/c/cpp)

2017.07.06NOIP提高模擬B

T1:  FJ出去砍木材去了,把N(2<=N<=100,000)頭牛留在家中吃草,當他回來的時候,發現奶牛們都跑到花園裡吃花去了,為了減少損失,FJ打算把牛移到牛棚中去。   每頭牛的位置離牛棚需要Ti分鐘(1<=Ti<=2,000

2017-07-08NOIP提高模擬B-連通塊(connect)-題解

原題: 題目描述: 你應該知道無向圖的連通塊的數量,你應該知道如何求連通塊的數量。當你興奮與你的成就時,破壞王Alice拆掉了圖中的邊。當她發現,每刪去一條邊,你都會記下邊的編號,同時告訴她當前連通塊的個數。 然而,對邊編號簡直就是個悲劇,因為A

2017.08.14NOIP 普及模擬C總結

好久沒考好了。。十分尷尬,發誓要考好! 第一題,羊羊整除。 難度:D組第二題~C組第一題。 模擬不多說。 第二題,羊羊吃草。 難度:D組第三題~C組第三題- 二分列舉,淼淼! 第三題,羊羊修路。 最小

2017.04.02NOIP 普及模擬C T2:士兵

士兵 題目描述 在Gridland國家,有N個處於不同位置的士兵。該國上的地方都用兩個座標(X,Y)來表示。士兵能進行一次移動,每個士兵都可向上、向下、向左、或向右移動一個單位長,這樣他就能把自己的X或Y改變1或-1。 士兵們想進入一個水平線,彼此靠近,這

2017.08.05NOIP提高模擬B

第一題 mar pan soft 提高 題目 mil font cal Summary   這次比賽打得非常差,第一題我以為是個難題,於是推了一下就沒再去想了,然而考場上一堆人AC。第二題狀態設錯了,導致結果有後效性。結束後pascal卡常卡了36次。第三題別人n&sup

2017.10.06NOIP提高模擬B 青蛙 題解

傳送門 Description 有n片荷葉在池塘上。因為如此這般,有一隻年輕的青蛙要在荷葉上跳。它是這樣跳的:假如它在第i 號荷葉上,那麼它等概率地跳到1 到i 號的荷葉中的一個,跳到1 號荷葉結束。求這隻青蛙期望跳多少次結束。 Input 一行

2017.08.05NOIP提高模擬B總結

好久沒寫過比賽總結了~ 今天的比賽真是難~比賽的時候160分:100+30+30=160分。 下面就每題總結一下吧: T1:袁紹的刁難(recruitment.pas/cpp) http://172.16.0.132/senior/#contest/s

2016.12.30初中部 GDKOI模擬B

總結: 這次比賽做的比較差,沒有發揮出應有的水平,像第一題這種可以稱之為“一眼題”的題目,竟然一分沒拿,找找原因,發現還是比賽時不夠認真,座標說了全部>0,為什麼還考慮負數?題目提醒了資料的範圍

2016.12.17初中部 GDKOI 模擬B

T1: 顯然,因為不能有兩個決策不一樣,則如果有一決策不一樣,對應的決策就確定了,所以依次特性,連一個圖,如樣例,f'N','N'=true  f'Y''Y'=true......如果某一點是以一決