百度之星2020 初赛一

D r i n k Drink

签到题

int n,m,ans;

int main() {
	int _;qr(_); while(_--) {
		qr(n); qr(m); ans=1e9;
		for(int i=1;i<=n;i++) {
			int x,y; qr(x); qr(y);
			ans=min(ans,((m-1)/x+1)*y);
		}
		pr2(ans);
		
	}
	return 0;
}

G P A GPA

比赛的时候没有多想直接打表.

double f[N],g[N];

int main() {
	for(int i=95;i<=100;i++) g[i]=4.3;
	for(int i=90;i<=94;i++) g[i]=4;
	for(int i=85;i<=89;i++) g[i]=3.7;
	for(int i=80;i<=84;i++) g[i]=3.3;
	for(int i=75;i<=79;i++) g[i]=3;
	for(int i=70;i<=74;i++) g[i]=2.7;
	for(int i=67;i<=69;i++) g[i]=2.3;
	g[65]=g[66]=2;
	for(int i=62;i<=64;i++) g[i]=1.7;
	for(int i=60;i<=61;i++) g[i]=1;
	for(int i=0;i<=100;i++)
		for(int j=0;j<=100;j++)
			for(int k=0;k<=100;k++)
				for(int x=0;x<=100;x++)
					f[i+j+k+x]=max(f[i+j+k+x],g[i]+g[j]+g[k]+g[x]);
	int _;qr(_); while(_--) {
		int n;qr(n);
		printf("%.1lf\n",f[n]);
	}
	return 0;
}

实际上,每个绩点取最低分数即可.复杂度可以降至: O ( 1 1 4 + q ) O(11^4+q) .

D e c Dec

直接 n 2 n^2 dp.

int f[N][N],n,m;

int main() {
	n=1000;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			f[i][j]=max(f[i-1][j],f[i][j-1])+(gcd(i,j)==1);
	int _;qr(_); while(_--) {
		qr(n); qr(m);
		pr2(f[n][m]);
	}
	return 0;
}

C i v i l i z a t i o n Civilization

恶心的语文题.

直接枚举城市建在哪里,然后每次把新人贪心安排在最大的点即可.

普及一个小小技巧: n > > 1 n>>1 n / 2 n/2 是在整数运算上是不一样的.

n > > 1 n >>1 ,是相当于 f l o o r ( n / 2 ) floor(n/2) .

n / 2 n/2 ,对于非负整数 n n ,则相当于 f l o o r ( n / 2 ) floor(n/2) ,但是对于负数则为 c e i l ( n / 2 ) ceil(n/2) .

本质上是把小数部分舍去了.

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<vector>
#define ll long long 
using namespace std;
const int N=505;
int d[20];
int cnt[5],n,a[N][N];
bool pd(int x,int y){return 1<=x&&x<=n&&1<=y&&y<=n;}
int calc(int x,int y)
{
	int ans=0,s=a[x][y];
	memset(cnt,0,sizeof(cnt));
	for(int i=3;i>=-3;--i)
	{
		int w=3-abs(i);
		for(int j=-w;j<=w;++j)
		{
			if(pd(x+i,y+j))++cnt[a[x+i][y+j]];
		}
	}
	cnt[s]--;
	int tot=1,sum=0;
	while(tot<9) {
		sum+=s; ans++;
		if(d[tot]<=sum) {
			tot++;
			for(int i=3;i;i--) 
				if(cnt[i]) {
					s+=i;
					cnt[i]--;
					break;
				}
		}
	}
	return ans;
}
int main()
{
	int t;scanf("%d",&t);
	for(int i=1;i<=9;i++)d[i]=8*i*i;
	while(t--)
	{
		int x,y;scanf("%d%d%d",&n,&x,&y);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				scanf("%d",&a[i][j]);
		int ans=0x3f3f3f3f;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=n;j++)
			{
				int wd=abs(x-i)+abs(y-j);
				ans=min(ans,calc(i,j)+((wd-1)>>1)+1);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

R o t a t e Rotate

简单概率题

因为 a a 是递增的,所以同层不会有两个黑同时连在一个上层黑.(对于两层 a a 相等的情况,只有一种情况是不满足的,但是算概率的时候我们是算长度占总长度的,所以可以忽略这种情况).所以这是一个森林,森林的连通块数=点数-边数.

在这里插入图片描述

我们单独考虑一个黑块是否和上一层的黑块不合并.

不合并的概率为 ( 1 x 1 y ) / 2 x = ( 1 x y ) / 2 (\dfrac 1 x-\dfrac 1 y)/\dfrac 2 x=(1-\dfrac x y)/2 (考虑上面那块在 2 / x 2/x 的长度上移动,取不相邻时的开头长度/总长度)

由于这一层有 y / 2 y/2 个黑,所以这层的总贡献为 ( y x ) / 4 (y-x)/4 .

特别的,对于第一层开始有 x / 2 x/2 个,所以 a n s = ( a [ 1 ] + a [ n ] ) / 4 ans=(a[1]+a[n])/4 .

int n,a[N];
ll ans,inv=(mod+1)/2;

int main() {
	int _;qr(_); while(_--) {
		qr(n); ans=0;
		for(int i=1;i<=n;i++) qr(a[i]);
		ans=(a[1]+a[n])/2*inv%mod;
		pr2(ans);
	}
	return 0;
}

M a t r i x Matrix

肯定贪心选择权值小的,然后我们枚举一下覆盖次数,计算一下每次的合法格点数.

复杂度为 O ( k ) O(\sqrt k) .

ll l[4],k,ans; 

ll f(ll x,ll y) {//边长,曼哈顿距离
	if(x>=y) {
		if(!y) return 1;
		return 4*y;
	}
	else return 4*max(2*x-y+1,0LL);
}

int main() {
	int _;qr(_); while(_--) {
		for(int i=0;i<4;i++) qr(l[i]); 
		qr(k); ans=0;
		for(int i=0;k;i++) {//枚举贡献 
			ll t=0;
			for(int j=1;j<=4;j++) if(i%j==0) {//枚举覆盖次数 
				int k=i/j;
				t+=f(l[4-j],k);
				if(j!=4) t-=f(l[3-j],k);//容斥
			}
			t=min(t,k); k-=t;
			ans+=t*i;
		}
		pr2(ans);
	}
	return 0;
}

M o s q u i t o Mosquito

网络流好题.

虽然考试时候也想到网络流,但是实在太劣了, O ( log n ) O(\log n) 二分, O ( n m n m ) O(nm\sqrt{nm}) 暴力匹配,其实单做一次就会T.

正解十分巧妙,定义 f [ i ] [ j ] f[i][j] 表示 i i 时刻内 j j 这个状态(对窗户进行状压,1表示有这个窗户)能到达的格点数,这个可以通过 O ( n m k + n 2 k ) O(nmk+n2^k) 的预处理实现.

然后对于一个时间 t t ,这样构建流图:

  1. s t i ( z [ i ] ) ( i [ 1 , k ] ) st\rightarrow i(z[i])(i\in[1,k])
  2. i j + k + 1 ( i n f ) ( j & ( 1 < < i ) ) i\rightarrow j+k+1(inf)(j\&(1<<i))
  3. j + k + 1 e d ( f [ t ] [ j ] ) j+k+1\rightarrow ed(f[t][j])

这个的点数只有 2 k 2^k ,所以可以轻松跑.

#include<bits/stdc++.h>
#define pi pair<int,int>
#define fi first
#define se second
using namespace std;
const int N=2005,M=8,inf=2e9;

void qr(int &x) {scanf("%d",&x); }

namespace flow {
	const int N=1<<7,M=N*30;
	int st,ed,d[N],c[N],q[N];
	struct edge{int y,next,c;} a[M]; int len,last[N],cur[N];
	void clear() {memset(last,0,sizeof(int[ed+1])); len=1;}
	void ins(int x,int y,int c) {a[++len]=(edge){y,last[x],c}; last[x]=len;}
	void add(int x,int y,int c) {ins(x,y,c); ins(y,x,0);}
	void bfs() {
		for(int i=0;i<=ed;i++) c[i]=d[i]=0,cur[i]=last[i];
		int l,r; q[l=r=1]=ed; ++c[d[ed]=1];
		for(int x=ed;l<=r;x=q[++l])
			for(int k=last[x],y;k;k=a[k].next)
				if(!d[y=a[k].y]) {++c[d[y]=d[x]+1]; q[++r]=y;}
	}
	int dfs(int x,int f) {
		if(x==ed) return f;
		int s=0,t;
		for(int &k=cur[x],y,z;k;k=a[k].next) {
			y=a[k].y; z=min(a[k].c,f-s);
			if(z&&d[y] == d[x]-1) {
				s += t = dfs(y,z);
				a[k].c -= t; a[k^1].c += t;
				if(s == f) return s;
			}
		}
		if(!--c[d[x]]) d[st]=ed+1;
		++c[++d[x]]; cur[x]=last[x]; return s;
	}
	int dicnic() {
		int s=0; bfs();
		while(d[st]<=ed) s+=dfs(st,inf);
		return s;
	}
}

int n,m,k,x[M],y[M],z[M],f[N][1<<M];

bool check(int x) {
	int st=(1<<k)+k,ed=st+1;
	flow::st=st; flow::ed=ed; flow::clear();
	for(int i=0;i<k;i++) flow::add(st,i,z[i]);
	for(int i=0;i<(1<<k);i++) {
		flow::add(i+k,ed,f[x][i]);
		for(int j=0;j<k;j++) if(i>>j&1) 
			flow::add(j,i+k,inf);
	}
	return flow::dicnic()==n*m;
}

int main() {
	int T; qr(T); while(T--) {
		memset(f,0,sizeof f);
		qr(n); qr(m); qr(k);
		for(int i=0;i<k;i++) qr(x[i]),qr(y[i]),qr(z[i]);
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++) {
				vector<pi> cur(k);
				for(int t=0;t<k;t++) 
					cur[t]=make_pair(abs(x[t]-i)+abs(y[t]-j),t);
				sort(cur.begin(),cur.end());
				for(int t=0,tot=0;t<k;t++) {
					tot |= 1 << cur[t].se;
					f[cur[t].fi][tot]++;
					if(t < k - 1) f[cur[t+1].fi][tot]--;
				}
			}
		int l=0,r=n+m,mid;
		for(int i=1;i<=r;i++)
			for(int j=0;j<(1<<k);j++)
				f[i][j] += f[i-1][j];
		if(!check(r)) puts("-1");
		else {
			while(l<r) {
				mid=(l+r)/2;
				if(check(mid)) r=mid;
				else l=mid+1;
			}
			printf("%d\n",l);
		}
	}
	return 0;
}

F u n c t i o n Function

莫比乌斯反演好题.(数学推导能力又下降了…

{ a n s = i = 1 n i j = 1 n / i [ ( i , j ) = 1 ] = i = 1 n i j = 1 n / i d i , d j μ ( d ) = d = 1 n μ ( d ) i = 1 n / d i d n i d 2 T = i d 2 , = T = 1 n n T d 2 T T / d μ ( d ) = d = 1 n μ ( d ) d i = 1 n / d 2 n i d 2 i G ( n ) = i = 1 n n i i ( ) = d = 1 n μ ( d ) d G ( n / d 2 ) \begin{cases} ans &=\sum_{i=1}^n i\sum_{j=1}^{n/i} [(i,j)=1] \\ &= \sum_{i=1}^ni\sum_{j=1}^{n/i} \sum_{d|i,d|j} \mu(d) \\ &= \sum_{d=1}^n \mu(d)\sum_{i=1}^{n/d} id*\lfloor \dfrac n {id^2}\rfloor \\ &设T=id^2, \\ &=\sum_{T=1}^n \dfrac n T \sum_{d^2|T} T/d*\mu(d) \\ &=\sum_{d=1}^{\sqrt n} \mu(d)d\sum_{i=1}^{n/d^2} \lfloor\dfrac n {id^2} \rfloor i\\ &设G(n)=\sum_{i=1}^n \lfloor\dfrac n i\rfloor i(本质上是约数和的前缀和)\\&=\sum_{d=1}^{\sqrt n} \mu(d)dG(\lfloor n/d^2\rfloor)\end{cases}

上面有些向下取整忽略掉了,希望不影响阅读.

m = n m=\sqrt n ,则我们需要 O ( m ) O(m) 预处理 μ ( d ) d \mu(d)d 的前缀和, O ( m log m ) O(m\log m) 预处理约数和.

G ( n ) G(n) 的复杂度是 O ( m ) O(m) 的,总共调用G的复杂度为 i = 1 n n / d 2 = m i = 1 m 1 i = m log m \sum_{i=1}^{\sqrt n} \sqrt {n/d^2}=m\sum_{i=1}^m \dfrac 1 i=m\log m

#include<map>
#include<set>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
#define IT iterator
#define SZ(a) ((int)a.size())
#define all(a) a.begin(),a.end()
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int N=1e6+10,size=1<<20,mod=1e9+7,inv=(mod+1)/2;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

//math
ll mult(ll a,ll b,ll p) {
	a=(a%p+p)%p; b=(b%p+p)%p;
	ll c=(ld)a*b/p;
	return a*b-c*p;
}
ll gcd(ll a,ll b) {return !a?b:gcd(b%a,a);}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
ll power(ll a,ll b=mod-2) {
	ll c=1;
	while(b) {
		if(b&1) c=c*a%mod;
		b /= 2; a=a*a%mod;
	}
	return c;
}
ll Power(ll a,ll b=mod-2) {
	ll c=1;
	while(b) {
		if(b&1) c=mult(c,a,mod);
		b /= 2; a=mult(a,a,mod);
	}
	return c;
}

int prime[N],tot,mu[N],g[N]; bool v[N];
void upd(int &x) {x-=(x>=mod)*mod; x+=x>>31&mod;}

void get(int x) {
	mu[1]=1;
	for(int i=2;i<=x;i++) {
		if(!v[i]) prime[++tot]=i,mu[i]=-1;
		for(int j=1,k;(k=i*prime[j])<=x;j++) {
			v[k]=1;
			if(i%prime[j]) mu[k]=-mu[i];
			else break;
		}
	}
	for(int i=1;i<=x;i++) {
		upd(mu[i]=mu[i-1]+mu[i]*i);
		for(int j=i;j<=x;j+=i) upd(g[j]+=i);
	}
	for(int i=1;i<=x;i++) upd(g[i]+=g[i-1]);
}

ll calc(ll n) {
	if(n<N) return g[n];
	ll s=0;
	for(ll l=1,r;l<=n;l=++r) {
		r=n/(n/l);
		s+= (r-l+1)%mod*((r+l)%mod)%mod*inv%mod*((n/l)%mod)%mod;
	}
	return s%mod;
}

int main() {
	get(N-1);
	int _;qr(_); while(_--) {
		ll n,ans=0;qr(n);
		for(ll l=1,r;l*l<=n;l=++r) {
			r=l;
			while(n/(r+1)/(r+1)==n/l/l) ++r;
			ans += (mu[r]-mu[l-1]+mod) * calc(n/l/l) % mod;
		}
		pr2(ans%mod);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/107466490