シミュレーション2019CSP-S

T1

説明

正の整数Sを与え、それはそれらの合計がSより大きくないように、互いに異なる正の整数の複数を選択するように要求し、
各因子(それ自体は含まない)と最大合計数。

入力

S.の数を入力します。

出力

数のANSの出力

サンプル

サンプル入力1
4
1.5サンプル出力1
3
1.6サンプル入力2
6
1.7サンプル出力2
6

データ範囲

30%、S≤10のデータ。
データの100%に、≤1000 S。

思考

典型的なナップザック問題

コード

#include <bits/stdc++.h>
#define int long long
using namespace std;
int s;
int sum[1005];
inline int read(){
	int cnt=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')	f=-f;c=getchar();}
	while(isdigit(c)){cnt=(cnt<<3)+(cnt<<1)+(c^48);c=getchar();}
	return cnt*f;
}
signed main(){
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	s=read();
	for(int i=1;i<=s;i++){
		for(int j=1;j<=i/2;j++){//任何一个因数都不会超过i/2
			if((i%j)==0){
				sum[i]+=j;//预处理出因数和
			}
		}
	}
	for(int i=1;i<=s;++i){//枚举当前
		for(int j=1;j<=i/2;++j){
			sum[i]=max(sum[i],sum[j]+sum[i-j]);//sum类似于前缀和
		}
	}
	printf("%lld",sum[s]);
	return 0;
}

T2T2

思考:+単調バイナリ最適化キュー

単調キューは、一般的に単調増加と単調減少の2種類が一般的に単調を有するキューが存在する場合、キューの先頭には、キューの最大キューは、全体又は最小で
実装:キューが空である場合、A [i]がチームからテールがエンキュー
キューが空でない場合、Aより[i]の要素は、[i]は、その後、チームの大端から排出されるエンキューされ
たキューが空でないときには[i]を直接チームから、テールよりも大きく、 A [i]がエンキューの端

コード

合計:マイナスプレフィックスと平均値の
列挙でチェック

  1. 私は右のエンドポイントの列挙であることに注意してください
  2. - L iLは - R iRの 列挙点範囲の左端
  3. Q E その 最小配列の接頭辞によって維持単一のキューと s u m (和 )
    ご注意ください 単調なキューのメンテナンスのみのみ最小値と最大値を考慮して適用すると、キューの状態をポップ答え(決定単調)への影響はありません
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+50;
int n,L,R,a[N];
double mid;
inline int read()
{
    char ch = getchar();int i = 0, f = 1;
    while (!isdigit(ch)){if (ch == '-')f = -1;ch = getchar();}
    while (isdigit(ch)){i = (i << 1) + (i << 3) + ch - '0';ch =getchar();}
    return i * f;
}
bool check(double v){
	static double sum[N],que[N];
	static int head,tail,pos[N];
	head=1;tail=0;
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+1.0*a[i]-v;
	}
	for(int i=L;i<=n;i++){
		while(head<=tail&&que[tail]>=sum[i-L]){
			tail--;//如果单调队列最末大于现在值,不断出队以维护单调性
		}
		while(head<=tail&&pos[head]+R<i){//pos[head]<i-R此时已经不可能作为左端点,出队
			head++;
		}
		que[++tail]=sum[i-L];
		pos[tail]=i-L;
		if(sum[i]-que[head]>=0){
			return true;
		}
	}
	return false;
}
int main(){
	n=read(),L=read(),R=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
	}
	double l=0,r=1e6;
	for(int i=1;i<=100;i++){
		mid=(l+r)/2;
		if(check(mid)){
			l=mid;
		}
		else	r=mid;
	}
	printf("%.4lf\n",mid);
	return 0;
}

T3

トピック[ウォレス]タイトル説明

思考

エッジに参加するかどうかを決定する際に、このエッジの両端が接続されていたならば、我々はブロックがリンクリングを持っているかどうかを知る必要があります。なし場合、このエッジを追加することができ、かつ両端クロスリングを介して、ブロックが新しいブロックがユニコム環を有するかどうかを取得している場合。
そこにリングかどうかへの接続、追加のメンテナンスユニコムブロックを維持するために、互いに素-セットで。

  1. 同じツリーの両端:仲裁リング、リング:偽関節;ノーリング:ダブル
  2. 2つのツリーの両端:調停リング、二つのリングは、次のとおり不連続;バランス:さえ

コード

何のリングアレイ記録帳はありません
FAメンテナンス互いに素-セット
TOTを接続されたエッジの数は、 ( 木もエッジと、そうではありません n 1 ) N-1)
及びチェック情報のセット、合わせループ

#include <bits/stdc++.h>
using namespace std;
int fa[500050],book[500050];

struct node{
	int x,y,w;
}a[500050];
bool cmp(const node &a,const node &b){
	return a.w<b.w;
}
inline char nc(){//超级快读
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int getf(int x){
	return fa[x]==x?x:fa[x]=getf(fa[x]);
}
int main(){
	int n,m,i,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)  fa[i]=i;
	for(i=1;i<=m;++i)  scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
	sort(a+1,a+m+1,cmp);//按边权排序
	long long tot=0,ans=0;
	for(int i=1;i<=m;i++){
		x=getf(a[i].x),y=getf(a[i].y);
		if(x==y&&!book[x]){
			book[x]=1;tot++;ans+=a[i].w;
		}
		else{
			if(book[x]&&book[y])	continue;
			fa[x]=y;book[y]=book[x]|book[y];
			tot++;ans+=a[i].w;
		}
	}
	if(tot!=n){
		printf("No"); 
	}
	else{
		printf("%lld",ans);
	}
	return 0;
	
}
公開された37元の記事 ウォン称賛11 ビュー1949

おすすめ

転載: blog.csdn.net/weixin_42750325/article/details/102470476