天天看點

Week4 W (A-DDL 的恐懼)(B-四個數列)(C-TT 的神秘禮物 )A-DDL的恐懼B-四個數列C-TT的神秘禮物

文章目錄

  • A-DDL的恐懼
    • 題意
    • 思路
    • 代碼
  • B-四個數列
    • 題意
    • 思路
    • 代碼
  • C-TT的神秘禮物
    • 題意
    • 思路
    • 代碼

A-DDL的恐懼

題意

ZJM 有 n 個作業,每個作業都有自己的 DDL,如果 ZJM 沒有在 DDL 前做完這個作業,那麼老師會扣掉這個作業的全部平時分。

是以 ZJM 想知道如何安排做作業的順序,才能盡可能少扣一點分。

Input

輸入包含T個測試用例。輸入的第一行是單個整數T,為測試用例的數量。

每個測試用例以一個正整數N開頭(1<=N<=1000),表示作業的數量。

然後兩行。第一行包含N個整數,表示DDL,下一行包含N個整數,表示扣的分。

Output

對于每個測試用例,您應該輸出最小的總降低分數,每個測試用例一行。

思路

貪心就完了

先按照扣的分數從大到小排個序(扣分較多的比較重要)

盡量把所有作業安排到ddl當天做,那天實在沒辦法做就向前尋找空閑的時間做。這裡可以開n個桶來代表有n天,我們向前尋找的時候隻要看這個桶是否被一個作業占用,否就占用,是就往前找,直到第0個桶,也就是這個作業做不了了,此時答案 ans 加上這題所扣的分

代碼

#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<iomanip>
#define llong long long
#define For(i,a,n) for(register int i=a;i<=n;i++)
#define RF(i,a,n) for(register int i=a;i>=n;i--)
#define inf 1e9
#pragma GCC optimize(2)
using namespace std;

const int maxn = 100005;
struct node{
    int t, p;
    bool operator < (const node &b) const{
        return p>b.p;
    }
}a[maxn];
int b[maxn];
int T, n;

int main(){
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--){
        memset(b,0,sizeof(b));
        int ans = 0;
        cin>>n;
        For(i,1,n) cin>>a[i].t;
        For(i,1,n) cin>>a[i].p;
        sort(a+1,a+1+n);
        For(i,1,n){
            int t = a[i].t;
            while(t && b[t]) {t--;}
            if(t==0) ans+=a[i].p;
            b[t] = 1;
        }
        cout<<ans<<endl;
    }
    return 0;
}
           

————————————————————————————————————————————

B-四個數列

題意

ZJM 有四個數列 A,B,C,D,每個數列都有 n 個數字。ZJM 從每個數列中各取出一個數,他想知道有多少種方案使得 4 個數的和為 0。

當一個數列中有多個相同的數字的時候,把它們當做不同的數對待。

Input

第一行:n(代表數列中數字的個數) (1≤n≤4000)

接下來的 n 行中,第 i 行有四個數字,分别表示數列 A,B,C,D 中的第 i 個數字(數字不超過 2 的 28 次方)

Output

輸出不同組合的個數。

思路

這題資料比較大,直接周遊想必是不行的,對于這類查找的問題,周遊不行那就二分吧

因為是找a+b+c+d四個數的和為0的組合數,并不用寫出具體的數字,所有我們可以合并一下a和b,c和d。

那麼現在問題就變成了簡單的 A + B = 0 (A=a+b, B=c+d)的問題,移項得到 B = -A。

最終我們隻需要周遊A中的所有元素,去B中二分地尋找-A。

代碼

#include<iostream>
#include<algorithm>
#define llong long long
#define For(i,a,n) for(register int i=a;i<=n;i++)
using namespace std;

const int maxn = 20000005;
int n, ans;
int a[10][maxn];

int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    For(i,1,n){
    	For(j,1,4){
    		cin>>a[j][i];
    	}
    }
    int tot = 0;
    For(i,1,n){
    	For(j,1,n){
    		a[5][++tot] = a[1][i]+a[2][j];
    		a[6][tot] = a[3][i]+a[4][j];
    	}
    }
    sort(a[6]+1,a[6]+tot+1);
    For(i,1,tot){
    	int pos1 = lower_bound(a[6]+1,a[6]+tot+1,-a[5][i])-a[6];
		int pos2 = upper_bound(a[6]+1,a[6]+tot+1,-a[5][i])-a[6];
		if(pos1 != pos2) 
			ans += pos2-pos1;
    }
    cout<<ans<<endl;
    return 0;
}
           

————————————————————————————————————————————

C-TT的神秘禮物

題意

TT 是一位重度愛貓人士,每日沉溺于 B 站上的貓咪頻道。

有一天,TT 的好友 ZJM 決定交給 TT 一個難題,如果 TT 能夠解決這個難題,ZJM 就會買一隻可愛貓咪送給 TT。

任務内容是,給定一個 N 個數的數組 cat[i],并用這個數組生成一個新數組 ans[i]。新數組定義為對于任意的 i, j 且 i != j,均有 ans[] = abs(cat[i] - cat[j]),1 <= i < j <= N。試求出這個新數組的中位數,中位數即為排序之後 (len+1)/2 位置對應的數字,’/’ 為下取整。

Input

多組輸入,每次輸入一個 N,表示有 N 個數,之後輸入一個長度為 N 的序列 cat, cat[i] <= 1e9 , 3 <= n <= 1e5

Output

輸出新數組 ans 的中位數

思路

這題如果枚舉,C(n,2)且n<=1e5,肯定TLE。然而這題是求中位數,是以又可以二分了

題目要求的是 a[j] - a[i] <= d =====> a[j] <= a[i] + d

這就很神奇了,我們本來要求的是一個新的數組的中位數,現在可以在原數組中解決了。

我們二分d,統計小于a[j]的個數。

🌰🌰:

設數組a = {1,2,3,4}

∴ abs(aj-ai) = {1,1,1,2,2,3}

中位數位置 pos = C(n,2)/2 = 3

最終 ans = 1

設 d = 2

i=1(索引從1開始)   1,2,3,4    a[j]=a[i]+d=3   小于a[j]的:2,3    cnt = 2
 i=2    			2, 3, 4      a[j]=a[i]+d=4   小于a[j]的:3,4	cnt = 2
 i=3    			3, 4    	 a[j]=a[i]+d=5   小于a[j]的:4		cnt = 1
 i=4   				 4    		 a[j]=a[i]+d=5   小于a[j]的:沒有	cnt = 0

cnt = 2+2+1+0 = 5 > pos = 3  不滿足(不是我們要找的中位數)
縮小範圍……
           

PS:這題cout白給。

代碼

#include<iostream>
#include<cstring>
#include<algorithm>
#define llong long long
#define For(i,a,n) for(register int i=a;i<=n;i++)
using namespace std;

const int maxn = 100005;

int n, tot;
int a[maxn];

int jg(int d)
{
	int cnt = 0;
	For(i,1,n){
		cnt += upper_bound(a+i+1,a+n+1,a[i]+d)-(a+i+1);
	}
	return cnt>=tot;
}

int main(){
    while(~scanf("%d",&n)){
    	For(i,1,n){
    		scanf("%d",&a[i]);
    	}
    	sort(a+1,a+n+1);

    	tot = n*(n-1)/2;
    	tot = (tot+1)/2;

    	int l = 0, r = a[n]-a[1]+1;
    	while(r-l>1){
    		int mid = (l+r)>>1;
    		if(jg(mid))
    			r = mid;
    		else
    			l = mid;
    	}
    	printf("%d\n",r);
    }

    return 0;
}
           

繼續閱讀