1. 程式人生 > >【NOIP2018模擬賽2018.10.27】

【NOIP2018模擬賽2018.10.27】

小貓爬山

【題目描述】:

Freda和rainbow飼養了N只小貓,這天,小貓們要去爬山。經歷了千辛萬苦,小貓們終於爬上了山頂,但是疲倦的它們再也不想徒步走下山了(嗚咕>_<)。

Freda和rainbow只好花錢讓它們坐索道下山。索道上的纜車最大承重量為W,而N只小貓的重量分別是C1、C2……CN。當然,每輛纜車上的小貓的重量之和不能超過W。每租用一輛纜車,Freda和rainbow就要付1美元,所以他們想知道,最少需要付多少美元才能把這N只小貓都運送下山?

【輸入描述】:

第一行包含兩個用空格隔開的整數,N和W。

接下來N行每行一個整數,其中第i+1行的整數表示第i只小貓的重量Ci。

【輸出描述】:

輸出一個整數,最少需要多少美元,也就是最少需要多少輛纜車。

【樣例輸入】:

5 1996
1
2
1994
12
29

【樣例輸出】:

2

【時間限制、資料範圍及描述】:

時間:1s 空間:128M

對於100%的資料,1<=N<=18,1<=Ci<=W<=10^8。

題意就是有n只貓,分別重wi,然後要裝進若干個承重為w的纜車裡,問最少用的纜車數。

正解應該是迭代加深深搜,但是lz貪心直接水過100分。。。

深搜不說了,貪心就是儘量讓體重最小的跟體重最大的坐在一起,能裝就裝。(感覺一般現實生活中我們也會這樣處理這種問題吧,但是前輩們說這種貪心不對,但我覺得沒有更優地做法了呀。。望知道的dalao告訴蒟蒻qwq)

程式碼5分鐘寫出來:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define gc getchar
#define ex pt('\n')
#define ko pt(' ')
const int MAXN = 20;
int n,w;
int v[MAXN],vis[MAXN]; 
int ans = 0;
void in(int &x)
{
	int num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}

int main()
{
	in(n); in(w);
	for(int i = 1;i <= n;i++) in(v[i]);
	sort(v+1,v+1+n);
	for(int i = 1;i <= n;i++)
	{
		if(vis[i]) continue;
		ans++;
		int now = v[i]; vis[i] = 1;
		for(int j = n;j >= i;j--)
			if(now + v[j] <= w && !vis[j]) 
				vis[j] = 1,now += v[j];
	}
	out(ans);
	return 0;
}

得分

這道題老師沒放出來題目orz

大概題意是:一位同學要在T時間內做n道題中的全部或是部分,每道題有一個題目難度ci,需要時間ti,在剩餘時間x時開始做第i道題並且能做完的話,就可以得到x*ci的分,問可以得到的最大得分。

很明顯是個01揹包問題,但是要注意的是dp順序必須按 價效比(ci/ti :cj/tj) 從大到小來進行,不然答案無法被正確更新(至於為什麼,我也不是很明白,但是經過模擬發現若順序不對,就會導致答案沒有被更新出來,似乎是被前面的不優的東西擠掉了空間)

因為除法很麻煩,還要處理浮點數,所以比較函式寫成 ci*tj > cj*ti  就好。

哦對了,我的方程意思是f[j]代表當前剩餘時間,最後答案明顯取個最大(也許就是f[0]?),由於是01揹包只能限制f從上一階段逆向列舉過來,保證只轉移一次。

但是呀我這裡方程意思是剩餘時間,那麼相對於揹包裝進j來說的逆向是從已經裝了m進行逆向列舉轉移,同時可以想到對於剩餘時間來說,就應該從0開始轉移到m才算是逆向,故方程如下程式碼。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define gc getchar
#define ex pt('\n')
#define ko pt(' ')
const int MAXN = 3e3 + 5;
int n,m;
struct score
{
	int t,c;
	bool operator < (const score &one) const
	{
		return c*one.t > one.c*t;
	}
}s[MAXN];
int f[10005];
int ans = 0;
void in(int &x)
{
	int num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void out(int x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}

int main()
{
	in(n); in(m);
	for(int i = 1;i <= n;i++) in(s[i].t),in(s[i].c);
	sort(s+1,s+1+n);
	for(int i = 1;i <= n;i++)
		for(int j = s[i].t;j <= m;j++)
			f[j-s[i].t] = max(f[j-s[i].t],f[j] + j*s[i].c);
	for(int i = 0;i <= m;i++) ans = max(ans,f[i]);
	out(ans);
	return 0;
}

迷路

Description
windy在有向圖中迷路了。 該有向圖有 N 個節點,windy從節點 0 出發,他必須恰好在 T 時刻到達節點 N-1。 現在給出該有向圖,你能告訴windy總共有多少種不同的路徑嗎? 注意:windy不能在某個節點逗留,且通過某有向邊的時間嚴格為給定的時間。

Input
第一行包含兩個整數,N T。 接下來有 N 行,每行一個長度為 N 的字串。 第i行第j列為'0'表示從節點i到節點j沒有邊。 為'1'到'9'表示從節點i到節點j需要耗費的時間。

Output
包含一個整數,可能的路徑數,這個數可能很大,只需輸出這個數除以2009的餘數。

Sample Input
【輸入樣例一】
2 2
11
00

【輸入樣例二】
5 30
12045
07105
47805
12024
12345


Sample Output
【輸出樣例一】
1

【樣例解釋一】
0->0->1

【輸出樣例二】
852

HINT
30%的資料,滿足 2 <= N <= 5 ; 1 <= T <= 30 。 100%的資料,滿足 2 <= N <= 10 ; 1 <= T <= 1000000000 。
這道題爆零了orz。。一般來說都會想到處理環(包括自環)吧。。於是打了個tarjan縮點,dfs求最短路,最後利用縮點得來的每個環路徑長短,進行拼湊T。失敗了orzorzorz,居然全錯。。

正解為矩陣乘法快速冪,可以知道這個圖本身就是一個矩陣,要是要走T次到達終點的話相當於每次自乘矩陣,每一條邊都是一種選擇的情況,先按矩陣乘法乘,那個加起來的值就是從一個點到另一個點的情況和。起點到終點答案就是f[1][n]。

但是這種情況只能處理每條邊邊權均為1的情況,若大於1則不能這麼處理了。

於是我們發現邊權只有0~9,0,1不需要考慮,2~9邊權的話就把一個點拆成2~9個點相連的邊權為1的邊,加在矩陣後面就好了,答案還是f[1][n]處取得。

計算怎麼加在後面詳細看程式碼就好了,就是那個calc函式。。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pt putchar
#define gc getchar
#define ko pt(' ')
#define ex pt('\n')
const int MAXN = 150;
const ll MOD = 2009;
int n,m,sum,T;
int ans[MAXN][MAXN],a[MAXN][MAXN],b[MAXN][MAXN];

inline int calc(int x,int y) {return (y-1)*n+x;}

void in(int &x)
{
	int num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void lin(ll &x)
{
	ll num = 0,f = 1; char ch = gc();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
	while(ch >= '0' && ch <= '9') {num = (num<<3) + (num<<1) + (ch-'0'); ch = gc();}
	x = num*f;
}
void out(ll x)
{
	if(x < 0) x = -x,pt('-');
	if(x > 9) out(x/10);
	pt(x % 10 + '0');
}

inline void mul()
{
	memset(b,0,sizeof b);
	for(int i = 1;i <= n*9;i++)
		for(int j = 1;j <= n*9;j++)
			for(int k = 1;k <= n*9;k++)
				b[i][j] = (b[i][j] + ans[i][k]*a[k][j]) % MOD;
	memcpy(ans,b,sizeof b);
}

inline void mulself()
{
	memset(b,0,sizeof b);
	for(int i = 1;i <= n*9;i++)
		for(int j = 1;j <= n*9;j++)
			for(int k = 1;k <= n*9;k++)
				b[i][j] = (b[i][j] + a[i][k]*a[k][j]) % MOD;
	memcpy(a,b,sizeof b);
}

inline void init()
{
	in(n); in(T);
	for(int i = 1;i <= n;i++)
	{
		for(int j = 1;j <= n;j++)
		{
			char ch = getchar();
			int num = ch-'0';
			if(!num) continue;
			a[i][calc(j,num)] = 1;
		}
		for(int j = 2;j <= 9;j++) a[calc(i,j)][calc(i,j-1)] = 1;
		getchar();
	}
}

inline void work()
{
	for(int i = 1;i <= n*9;i++) ans[i][i] = 1;
	while(T)
	{
		if(T & 1) mul();
		T >>= 1;
		mulself();
	}
	out(ans[1][n] % MOD);
}

int main()
{
	init();
	work();
	return 0;
}