2021.01.27【NOIP提升A組】模擬

5434. 【NOIP2017提升A組集訓10.30】Matrix

​ 咱們發現對於一個詢問K,答案必定是<k的,而且一個數只會出現它因子的個數的次數,for example:6=1*6,6*1,2*3,3*2;四次;c++

​ 因此咱們考慮二分答案,每次對於一個mid求 SUM=\(\sum_{i=1}^{mid}\frac{mid}{i}\),而後與k比較一下就好了,經典的問題。app

5435. 【NOIP2017提升A組集訓10.30】Graph

​ 這道題的作法很暴力,咱們能夠將邊權從小到大排序,而後一條一條加進去,若是有衝突,就把這個環中最小的邊刪除就好了。
​ Why?由於邊是從小到大的,加進來的邊只會愈來愈大,而咱們要求差值最小的,因此刪除最小的邊最優,同時這個操做也不影響圖自己的聯通性。因此也算是一個巧妙的想法吧。spa

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
using namespace std;
bitset<2001>e[2001];
int i,j,n,m,k,l,t,num,cnt,fa[2001],ff[2001][2001],aim,pd,bbz[20001],ans;
struct nup {int l,r,id,qz;}f[80001],heap[80001];
bool cmp(nup x,nup y){return x.qz<y.qz;}
int father(int x) {if(x!=fa[x]) return fa[x]=father(fa[x]);return x;}
void down(long long x)
{
	while(x*2<=num)
	{
		long long y=x*2;
		if(y+1<=num&&heap[y+1].qz<heap[y].qz) y++;
		if(heap[y].qz>=heap[x].qz) break;
		swap(heap[y].qz,heap[x].qz);swap(heap[y].id,heap[x].id);
		x=y;
	}
}
void dfs(int x,int father,int mi,int fx,int fy)
{
	if(x==aim)
	{
		pd=0;e[fx].reset(fy);e[fy].reset(fx);
		bbz[ff[fx][fy]]=1;ff[fx][fy]=ff[fy][fx]=0;
		return;
	}
	if(pd==0) return;
	for(int i=e[x]._Find_first();i!=e[x].size();i=e[x]._Find_next(i))
	if(i!=father)
	{
		if(f[ff[x][i]].qz<mi) dfs(i,x,f[ff[x][i]].qz,x,i);
		else dfs(i,x,mi,fx,fy);
	}
}
int main()
{
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	scanf("%d",&t);
	while(t>0)
	{
		t--;
		scanf("%d%d",&n,&m);
		for(i=1;i<=m;++i) scanf("%d%d%d",&f[i].l,&f[i].r,&f[i].qz);
		sort(f+1,f+1+m,cmp);
		memset(heap,0,sizeof heap);cnt=0;num=0;ans=987654321;
		memset(ff,0,sizeof ff);
		memset(bbz,0,sizeof bbz);
		for(i=1;i<=n;i++)fa[i]=i,e[i].reset();
		for(i=1;i<=m;i++)
		{
			int va1=father(f[i].l),va2=father(f[i].r);
			if(va1!=va2)
			{
				ff[f[i].l][f[i].r]=ff[f[i].r][f[i].l]=i;
				cnt++;fa[va1]=va2;e[f[i].l].set(f[i].r);e[f[i].r].set(f[i].l);
				num++;heap[num].qz=f[i].qz;heap[num].id=i;
			}
			else
			{
				aim=f[i].r,pd=1;dfs(f[i].l,0,987654321,0,0);
				num++;heap[num].qz=f[i].qz;heap[num].id=i;
				e[f[i].l].set(f[i].r);e[f[i].r].set(f[i].l);
				ff[f[i].l][f[i].r]=ff[f[i].r][f[i].l]=i;
			}
			if(cnt==(n-1))
			{
				while(bbz[heap[1].id]==1)
				{
					swap(heap[1].id,heap[num].id);swap(heap[1].qz,heap[num].qz);num--;down(1);
				}
				ans=min(f[i].qz-heap[1].qz,ans);
			}
		}
		if(ans==987654321) printf("-1\n");else printf("%d\n",ans);
	}
}

5436. 【NOIP2017提升A組集訓10.30】Group

​ 這也是一個很巧妙的題目,若是咱們設DP:f[i][j][k]表示如今完成了前i個,分了j組,和爲k,咱們能夠看到這很難轉移,又要記錄最大最小值什麼的,因此咱們不妨設f[i][j][k]表示完成前i個還有j組未完成分配極差和爲k(前提先將A1,A2,\(\cdots\),An從小到大排序),這時咱們就不用記錄最大最小值了,why?對於一個分組a1,a2,a3\(\cdots\cdots\)an(a1<a2<\(\cdots\cdots\)<an) 極差和=an-a1=\(\sum_{i=2}^{n}a[i]-a[i-1]\) ,因此咱們往未完成分配的組裏加上a[i]-a[i-1]的貢獻就好了。
​ 設 tmp=(a[i]-a[i-1])*j 接下來分類討論:
​ 1.新開一組第一個數是a[i],而且未完成:f[i][j+1][k+tmp]+=f[i-1][j][k];(由於有j個組是未完成的因此加上tmp沒問題,下一輪是a[i+1]-a[i],若是不加tmp則每一組就會少a[i]-a[i-1]; 新開的不用加)
​ 2.新開一組就只有一個數是a[i] :f[i][j][k+tmp]+=f[i-1][j][k];
​ if(j>0)
​ {
​ 3.a[i]加到舊的一組中,而且未完成:f[i][j][k+tmp]+=f[i-1][j][k]*j;(有j個組能夠選)
​ 4.a[i]加到舊的一組中,而且完成了:f[i][j-1][k]+=f[i-1][j][k]*j;
​ }
​ 就上面四種狀況記得取模 1000000007;code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mo=1000000007;
ll i,j,n,m,l,k,f[2][201][4001],a[10001],now,tmp,ans;
int main()
{
	freopen("group.in","r",stdin);
	freopen("group.out","w",stdout);
	scanf("%d%d",&n,&k);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);
	sort(a+1,a+n+1);
	f[0][0][0]=1;now=0;
	for(i=1;i<=n;i++)
	{
		now^=1;
		memset(f[now],0,sizeof f[now]);
		for(j=0;j<i;j++)
		{
			tmp=(a[i]-a[i-1])*j;
			for(l=0;l<=k;l++)	
			{
				if(tmp+l>k) break;
				f[now][j+1][l+tmp]+=f[1-now][j][l],f[now][j+1][l+tmp]%=mo;
				f[now][j][l+tmp]+=f[1-now][j][l];f[now][j][l+tmp]%=mo;
				if(j>0)
				{
				f[now][j][l+tmp]+=f[1-now][j][l]*j;f[now][j][l+tmp]%=mo;
				f[now][j-1][l+tmp]+=f[1-now][j][l]*j;f[now][j-1][l+tmp]%=mo;
				}
			}
		}
	}
	for(i=0;i<=k;i++) ans+=f[now][0][i],ans%=mo;
	printf("%lld",ans); 
	return 0;
}

完結撒花🌸🌸🌸🌸🌸🌸:happy:💠排序

相關文章
相關標籤/搜索