2018提高组模拟13

版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/83503924

20181027

T1 洛阳怀

【WOJ4150】

素数线性筛

GCD

数学推理

* _ *

多读几遍,不难发现:

  • 如果我们除以了前i个的GCD,那么i以后的都不能除了
  • 每个数的分数是它的好的质因数个数减去坏的质因数个数(打表可以发现)

所以我们记录一下每个数的好质因数的个数和坏质因数的个数,

再按记录一个前i个数的GCD的好质因数的个数和坏质因数的个数。

因为我们除以后面对前面是没有影响的,所以可以从后往前搜,

每次前i的GCD如果坏的多余好的就除掉,再同步记录一下lazy就好。

#include<iostream>
#include<cstdio>
#include<bitset>
#include<cctype>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x;
}
int t=0,pri[10000];
bitset<100010>c;
void find_prime(){
	for(int i=2;i<=100000;i++){
		if(!c[i])pri[++t]=i;
		for(int j=1;j<=t&&i*pri[j]<=100000;j++){
			c[i*pri[j]]=1;
			if(i%pri[j]==0)break;
		}
	}
}
int n,m,a[2010],b[2010],h;
int hao[2010],huai[2010],so[2010],si[2010];
bitset<1000000005>g;
void divide(int u){
	int x=a[u],j=1;
	while(pri[j]*pri[j]<=x){
		while(x%pri[j]==0){
			x/=pri[j];
			if(g[pri[j]])huai[u]++;
			else hao[u]++;
		}
		j++;
	}
	if(x>1){
		if(g[x])huai[u]++;
		else hao[u]++;
	}
}
int gcd(int x){
	int r;
	if(x>h){r=x;x=h;h=r;}
	while(x){
		r=x;
		x=h%x;
		h=r;
	}
	return h;
}
void divide_2(int x,int u){
	int j=1;
	while(pri[j]*pri[j]<=x){
		while(x%pri[j]==0){
			x/=pri[j];
			if(g[pri[j]])si[u]++;
			else so[u]++;
		}
		j++;
	}
	if(x>1){
		if(g[x])si[u]++;
		else so[u]++;
	}
}
int main(){
	n=read();m=read();
	find_prime();
	for(int i=1;i<=n;i++)
		a[i]=read();
	for(int i=1;i<=m;i++){
		b[i]=read();
		g[b[i]]=true;
	}
	h=a[1];divide(1);
	so[1]=hao[1];si[1]=huai[1];
	for(int i=2;i<=n;i++){
		divide(i);
		divide_2(gcd(a[i]),i);
	}
	int lazyo=0,lazyi=0,ans=0;
	for(int i=n;i>0;i--){
		so[i]-=lazyo;si[i]-=lazyi;
		if(si[i]>=so[i]){
			lazyo+=so[i];
			lazyi+=si[i];
		}
		hao[i]-=lazyo;huai[i]-=lazyi;
		ans+=(hao[i]-huai[i]);
	}
	printf("%d",ans);
	return 0;
}

T2 洗衣服

【WOJ2796】

贪心

* _ *

可以用堆。

我们给每一台机器都安排一个任务。

然后每次取堆顶(最快做完的),再安排一个任务,入堆。

这样取出最快的L个,加入一个数组。

洗衣机和烘干机都一样。

然后,根据排序不等式

在这里插入图片描述

两台机器,最大的配最小,再取一个MAX就是答案了 ^ _ ^

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x;
}
#define ll long long
int n,m,k,a[100010],b[100010];
ll l1[1000010],l2[1000010];
priority_queue< pair<ll,int> >q1;
priority_queue< pair<ll,int> >q2;
int main(){
	k=read();n=read();m=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
		q1.push(make_pair(-(ll)a[i],i));
	}
	for(int i=1;i<=m;i++){
		b[i]=read();
		q2.push(make_pair(-(ll)b[i],i));
	}
	for(int i=1;i<=k;i++){
		int y1=q1.top().second;
		ll x1=q1.top().first;q1.pop();
		l1[i]=-x1;q1.push(make_pair(x1-a[y1],y1));
		ll x2=q2.top().first;
		int y2=q2.top().second;q2.pop();
		l2[i]=-x2;q2.push(make_pair(x2-b[y2],y2));
	}
	ll ans=0;
	for(int i=1;i<=k;i++){
		ans=max(ans,l1[i]+l2[k-i+1]);
	}
	printf("%lld",ans);
	return 0;
}

T3 成绩单

【WOJ3175】

区间DP

* _ *

题解:%%%LDX%%%

在这里插入图片描述
最后应该是 +f[j+1][t]

不难发现,g 的第一位都没有变过,所以就强行压下了一维。

看完后,打一打代码,大概就懂了……

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x;
}
int n,m,a,b;
int c[60],h[60];
int f[55][55],g[55][55][55];
int main(){
	n=read();a=read();b=read();
	for(int i=1;i<=n;i++){
		c[i]=h[i]=read();
		f[i][i]=a;
	}
	sort(h+1,h+n+1);
	int m=unique(h+1,h+n+1)-h-1;
	for(int i=1;i<=n;i++)
		c[i]=lower_bound(h+1,h+m+1,c[i])-h;
	for(int len=2;len<=n;len++)
		for(int l=1,r=len;r<=n;l++,r++){
			for(int i=l;i<=r;i++)
				for(int j=m;j;j--)
					for(int k=m;k>=j;k--)
						g[i][j][k]=1<<30;
			g[l][c[l]][c[l]]=0;
			for(int i=l;i<r;i++)
				for(int j=m;j>0;j--)
					for(int k=m;k>=j;k--){
						if(g[i][j][k]==1<<30)continue;
						int e=min(j,c[i+1]),d=max(k,c[i+1]);
						g[i+1][e][d]=min(g[i+1][e][d],g[i][j][k]);
						for(int t=r;t>i;t--)
							g[t][j][k]=min(g[t][j][k],g[i][j][k]+f[i+1][t]);
					}
			f[l][r]=1<<30;
			for(int j=m;j;j--)
				for(int k=m;k>=j;k--)
					f[l][r]=min(f[l][r],g[r][j][k]+a+b*(h[j]-h[k])*(h[j]-h[k]));
		}
	printf("%d",f[1][n]); 
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42835823/article/details/83503924