其他分享
首页 > 其他分享> > 2022牛客多校7.23

2022牛客多校7.23

作者:互联网

A B C D E F G H I J K L M 总题数 通过题数
! ! O O ! O 12 3
Ø Ø O Ø Ø O Ø O 12 ?

赛后总结

G

证明见《离散数学》鸽巢原理
思想是分成\(\sqrt (n)\)个长度不超过\(\sqrt (n)\)的单增子序列,每个子序列按第一位数,从大到小排列

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,T; 
int main(){
	cin>>T;
	while(T--){
		cin>>n;
		int cnt=1;
		while(cnt*cnt<n)cnt++;
		for(int i=cnt;i>=1;i--)
			for(int j=i;j<=n;j+=cnt)
				printf("%d ",j);
		puts("");
	}
	return 0;
}
J

题意是求一个大系数二元二次函数的最小值(保证最小值存在)。
最值的求法只需用到两次二次函数最值,(每次削减一个变量)
若按此法,求解时会炸long double的精度,需要用__float128

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
__float128 A,B,C,D,E,F;
const int maxn=1e5+1000;
int n;
int a[maxn];
inline void read(int &x){
	x=0;int fl=1;char tmp=getchar();
	while(tmp<'0'||tmp>'9')fl=tmp=='-'?-fl:fl,tmp=getchar();
	while(tmp>='0'&&tmp<='9')x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
	x=x*fl;
}
signed main(){
//	freopen("std.txt","r",stdin);
	int T;cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;i++)
			read(a[i]);
		A=B=C=D=E=F=0;
		for(int i=1;i<=n;i++){
			A+=i*i,C+=2*i,D+=-2*i*a[i],E+=-2*a[i],F+=a[i]*a[i];
		}
		B=n;
		__float128 x,y,z;
		x=(-C/A*C/4+B),y=-C/A*D/2+E,z=F-D/A*D/4;
		long double ans=z-y/x*y/4;
		printf("%.12Lf\n",ans);
	}
	return 0;
}

为了防止精度爆炸,也可以直接用最小二乘法求线性回归(大概是出题思路)

  LD sx = 0, sxx = 0, sy = 0, sxy = 0;
  loop(i, 1, n) {
      sx += i;
      sxx += (LD)i * i;
      sy += a[i];
      sxy += (LD)i * a[i];
  }
  LD bb = (n * sxy - sx * sy) / (n * sxx - sx * sx);
  LD aa = (sxx * sy - sx * sxy) / (n * sxx - sx * sx);

  LD res = 0;
  loop(i, 1, n) {
      LD d = a[i] - (bb * i + aa);
      res += d*d;
  }
  printf("%.8Lf\n", res);
L

这题是队友做的,滚动数组优化空间

赛后补题

K

给一个初始括号串,和最终合法括号串的长度。问合法括号串的个数。
接受\(O(n^3)\)的复杂度
比赛时没仔细算复杂度,以为\(O(n^3)\)不可做。另外受到上次杭电比赛的影响,以为是区间dp。
仍需加强对dp的练习。
不考虑和初始括号串的lcs。那么合法括号串个数可以用g(i,j)数组来求,i->确定括号串的位数,j->左括号比右括号多的个数(右比左多则非法)
定义f(i,j,k)表示,确定合法串的前i位,左比右多k个,lcs至少为j位的状态的个数。

#include<bits/stdc++.h>
#define int unsigned int
using namespace std;
const int maxn=201;
const int mod=1e9+7;
int n,m;
int f[maxn][maxn][maxn];
char s[maxn];
signed main(){
	int T;cin>>T;
	while(T--){
		memset(f,0,sizeof f);
		f[0][0][0]=1;
		cin>>m>>n;
		scanf("%s",s+1);
		for(int i=1;i<=n;i++){
			for(int j=0;j<=i&&j<=m;j++)
				for(int k=0;k<=i;k++){
					printf("(%d,%d,%d): ",i,j,k);
					if(k){
						if(j&&s[j]=='(')f[i][j][k]=f[i-1][j-1][k-1],printf(">(%d,%d,%d)",i-1,j-1,k-1);
						else f[i][j][k]=f[i-1][j][k-1],printf(">(%d,%d,%d)",i-1,j,k-1);
					}
					if(j&&s[j]==')')f[i][j][k]+=f[i-1][j-1][k+1],printf("+(%d,%d,%d)",i-1,j-1,k+1);
					else f[i][j][k]+=f[i-1][j][k+1],printf("+(%d,%d,%d)",i-1,j,k+1);
					puts("");
					f[i][j][k]%=mod;
				}
		}
		cout<<f[n][m][0]<<endl;
	}
	return 0;
}
D

有向图上,找最大的系数w,使得边权均除去w后不存在边权相乘大于1的有向环。
这题比赛场上是另外两位队友负责,思路都是对的,就是没有注意处理好精度问题
首先w是一个二分答案,找环的过程可以用和找负环类似的做法,进队n次以上则环存在。
但若环的过于大,可能会导致dist数组溢出。
处理方式是对边权和w取log,把乘法转换为加法。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define pb push_back
#define SZ(x) ((int)(x).size())
#define mp make_pair
#define fi first
#define se second
#define all(x) x.begin(),x.end()
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef double db;
typedef long long ll;
const ll mod=1e9+7;
template<typename T>
inline void read(T &x){
	x=0;T fl=1;char tmp=getchar();
	while(tmp<'0'||tmp>'9')fl=tmp=='-'?-fl:fl,tmp=getchar();
	while(tmp>='0'&&tmp<='9')x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
	x=x*fl;
}
const int maxn=1100;
int n,m;
vector<pair<int,long double>>g[maxn];
long double dist[maxn];
int cnt[maxn];
bool inq[maxn];
bool check(long double w){
	queue<int>q;
	for(int i=1;i<=n;i++){
		dist[i]=cnt[i]=0,inq[i]=1;
		q.push(i);
	}
	while(!q.empty()){
		int u=q.front();q.pop(),inq[u]=0;
		cnt[u]++;
		if(cnt[u]>n)return 0;
		for(auto r:g[u]){
			if(dist[r.fi]<dist[u]+r.se+w){
				dist[r.fi]=dist[u]+r.se+w;
				if(!inq[r.fi]){
					q.push(r.fi);
					inq[r.fi]=1;
				}
			}
		}
	}
	return 1;
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		long double a,c;
		int b,d;
		scanf("%Lf %d %Lf %d",&a,&b,&c,&d);
		c=log(c/a);
		g[b].pb(mp(d,c));
	}
	long double l=0,r=1,mid,ans;
	while(r-l>=1e-8){
		mid=(l+r)/2;
		if(check(log(mid)))l=mid,ans=mid;
		else r=mid;
	}
	printf("%.10Lf\n",ans);
	return 0;
}

标签:tmp,int,多校,7.23,牛客,while,maxn,include,define
来源: https://www.cnblogs.com/xyc1719/p/16514487.html