第4週の割り当て

質問DDL恐怖

問題の説明

ZJMにはn個の課題があり、各課題には独自のDDLがあります。ZJMがDDLの前にこの課題を完了しない場合、教師はこの課題のすべての通常の課題を差し引きます。
したがって、ZJMは、控除をできるだけ少なくするために、宿題の順序を調整する方法を知りたいと考えています。
彼を助けてください!
input:
入力にはT個のテストケースが含まれます。入力の最初の行は、テストケースの数である単一の整数Tです。
各テストケースは、ジョブの数を示す正の整数N(1 <= N <= 1000)で始まります。
次に2行。最初の行にはDDLを示すN整数が含まれ、次の行には控除ポイントを示すN整数が含まれます。
出力:
テストケースごとに、テストケースごとに1行で、最小の合計削減スコアを出力する必要があります。

アイデア

今回は、構造を使用して、各ジョブのスコアとddlを保存します。毎回最高スコアの1つのジョブを取得して、ddlの前の日付が占有されているかどうかを確認します。占有されていない場合はそれを使用し、そうでない場合は破棄します。ここでvisを使用します配列は、日付が占有されているかどうかを示します。複数のデータセットがあるため、毎回0にリセットする必要があります。

コード
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

struct mm
{
	int t,v; 
	bool operator<(const mm&p)
	{
		return v>p.v;
	}
};
bool vis[1001];
mm shu[1002];
int n,T;
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		memset(vis,0,sizeof(vis));
		scanf("%d",&n);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&shu[i].t);
		}
		for(int i=0;i<n;i++)
		{
			scanf("%d",&shu[i].v);
		}		
		sort(shu,shu+n);
		int num=0 ;
		for(int i=0;i<n;i++)
		{
			bool flag=1;
			for(int j=shu[i].t;j>0;j--)
			{
				if(vis[j]==0)
				{
					vis[j]=1; 
					flag=0;
					break;
				}
			}
			if(flag)
				num+=shu[i].v;
		} 
		printf("%d\n",num);
	} 
	return 0;
}

まとめ

これは貪欲の典型的な問題でもあり、

質問B 4シリーズ

問題の説明

ZJMには4つのシリーズA、B、C、Dがあり、各シリーズにはn個の番号があります。ZJMは各シーケンスから数値を取得し、4つの数値の合計をゼロにするスキームの数を知りたいと考えています。シーケンスに同じ番号が複数ある場合は、それらを異なる番号として扱います。
彼を助けてください!
入力:
最初の行:n(シーケンスの番号の数を表す)(1≤n≤4000)
次のn行では、i番目の行に4つの番号があり、A、B、C、Dのシーケンスの番号を表しますI番目の数(数は2の28乗を超えない)
出力:
異なる組み合わせの数

アイデア

ここでは、二分法の考え方を使用できます。1つは4つの配列を持ち、2つは前と後を組み合わせて2つの配列を取得できます。0になる可能性がある数は、2つの配列の反対である必要があります。ソートするには、別の配列の各要素の反対の数を使用して、この配列の最初と最後のオカレンスを見つけ、オカレンスの数を取得します。合計数は、可能な組み合わせの数です。

コード
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int a1[4001],a2[4001],a3[4001],a4[4001]; 
int b1[16000111],b2[16000111];
int n;
int find(int t,int num)
{
	t*=-1;
	int first=-1,last=0;
	int l=0,r=num-1;
	bool f1=0;
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(b1[mid]>=t)
		{
			if(b1[mid]==t)f1=1;
			first=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	l=0;
	r=num-1;	
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(b1[mid]==t)
		{ 
			last=mid;
			l=mid+1;
			
		}
		else if(b1[mid]>t)r=mid-1;
		else l=mid+1;
	}
 	if(f1) {//printf("%d\n",t);
	return last-first+1;}
	else return 0;
	
}
int main()
{
	int num=0,count=0;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
       	scanf("%d%d%d%d",&a1[i],&a2[i],&a3[i],&a4[i]);
    for(int i=0;i<n;i++)
		for(int j=0;j<n;j++)
		{
			b1[num]=a1[i]+a2[j];
			b2[num++]=a3[i]+a4[j];
			   }   	
	sort(b1,b1+num);
 	for(int i=0;i<num;i++)
	{
		count+=find(b2[i],num);
	}
	cout<<count<<endl;
	return 0;
}

まとめ

悲しいかな、最初にクラスでpptを調べたときに邪悪な反対の番号が書かれていましたが、
間違った答えを得るたびに、配列で反対の番号を見つけるのを忘れていましたo(╥﹏╥)o

C質問DDL恐怖

問題の説明

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の位置に対応する数値であり、「/」は切り捨てられます。
TTはとてもかわいい猫を飼いたいのですが、手伝ってもらえますか?
入力:
複数の入力セット。Nを入力するたびにNの数があることを示し、次に長さNのシーケンスを入力しますcat、cat [i] <= 1e9、3 <= n <= 1e5
出力:
新しい配列の中央値数

アイデア

最初に元の配列を並べ替えて、新しい配列の要素値の範囲を計算します。この範囲で、バイナリの回答はPを見つけます(Pは中央値)。各Pについて、新しいシーケンスでのPのランクを計算します。
元の数値シーケンスが並べ替えられているため、絶対値に移動してXj <= Xi + Pを取得し、下付き文字iを列挙して、条件を満たす下付き文字jの数を計算できます。ここでの計算では、バイナリ検索を使用して最初の値以上の最初の値も検索しますXi + Pの数の位置、および条件を満たすすべてのjの合計は、条件を満たす2進タプルの対数です。数値と中央値のランクを比較してください。側では、ランクが中央値より大きい場合、中央値は左側にあり、新しい配列要素の値の範囲はそれに応じて更新されます。2つの数値が等しい場合、Pは中央値です。

コード
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int cat[100001];
int n;
int find(int t )
{ 
	int l=0,r=n-1,ans=-1; 
	while(l<=r)
	{
		int mid=(l+r)/2;
		if(cat[mid]>=t)
		{ 
			ans=mid;
			r=mid-1;
		}
		else l=mid+1;
	}
	return ans;
}
 
int main()
{
 	while(scanf("%d",&n)!=EOF)
 	{
 		for(int i=0;i<n;i++)
 		scanf("%d",&cat[i]);
 		sort(cat,cat+n);
 		int l=0,r=cat[n-1]-cat[0],ans=0;
 		int zh=(n*(n-1)/2+1)/2;
		  while(l<r)
        {
			//int mingci=0;
            int mid = (l+r)/2;
            int mingci = 0;
            for(int i=0;i<n;i++)
            {
                int rr = find(cat[i]+mid);//小于mid的个数 
                if(rr!=-1)
                mingci+= (n-rr);//计算mid名次 
            }
            if(mingci>(n*(n-1)/2-zh))//寻找第一个0出现 
            {
                ans = mid;
                l = mid +1;
            }
            else r = mid;
        } 
        cout<<ans<<endl;
	 }
	return 0;
}
まとめ

最初はPPTで与えられたアイデアについてあまり理解していませんでしたが、その後、具体的な意味を理解する前に長い間考えました。

元の記事を20件公開 賞賛3件 訪問数456件

おすすめ

転載: blog.csdn.net/qq_44893580/article/details/104979462