10.26 解题报告

T1

考场用时:\(2.5\) h
这题一直没有理解题意,然后去手模样例模不出来,看了很久题,题目所要求的是一个随机序列的期望顺序对数,容易发现对于一个固定的序列,不管怎么打乱它,逆序对与顺序对的个数只和不变,而顺序对与逆序对的地位完全相等,所以其期望个数也应当完全相等,所以答案即为 \(\frac{顺序对个数 + 逆序对个}{2}\)

#include<bits/stdc++.h>
#define ll long long
//#define int long long
//#define ull unsigned long long
#define lc(k) k<<1
#define rc(k) k<<1|1
#define lb lower_bound
#define orz cout<<"gzn ak ioi\n"
const int MAX=1e5+10;
const int MOD=1e9+7;
using namespace std;
inline char readchar() {
	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() {
#define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int a[MAX],t[MAX],c[MAX],n,m;
void add(int pos,int w){
	for(int i=pos;i<=m;i+=(i&-i)) c[i]+=w;
	return ;
}
int ask(int l,int r){
	int ret=0;
	for(int i=r;i;i-=(i&-i)) ret+=c[i];
	for(int i=l-1;i;i-=(i&-i)) ret-=c[i];
	return ret;
}
signed main(){
// 	freopen("calculation.in","r",stdin);
// 	freopen("calculation.out","w",stdout);
	int T=read(); 
	while(T--){
		n=read();
		for(int i=1;i<=n;i++){
			t[i]=a[i]=read();
			c[i]=0;
		}
		sort(t+1,t+1+n);
		m=unique(t+1,t+1+n)-t-1;
		for(int i=1;i<=n;i++) a[i]=lb(t+1,t+1+m,a[i])-t;
		ll ans1=0,ans2=0;
		for(int i=n;i>=1;i--){
			ans1+=ask(1,a[i]-1);
			ans2+=ask(a[i]+1,m);
			add(a[i],1);
//			cout<<ans1<<" "<<ans2<<endl;
		}
		if((ans1+ans2)&1) printf("%.2lf\n",(ans1+ans2)/2.0);
		else cout<<(ans1+ans2)/2ll<<endl;
	}
	return 0;
}
/*

1
3
1 2 3

*/

T3

考场用时:\(30\) min
这题最后做的,没时间想正解了,于是写了一个二分套bfs,没写完,所以很显然的得了零分。

考虑一个只要不出现像从上到下一溜圆连在一起封住了整个操场,那么当前的 \(dis\) 就是可行的,所以可以用并查集来维护连在一起的圆,最后查一下每个连通块上端点和下端点即可。

复杂度 \(O(n^2 \log n)\),常数比较小的话可以拿 \(100\) pts。

#include<bits/stdc++.h>
#define ll long long
#define int long long
//#define ull unsigned long long
#define lc(k) k<<1
#define rc(k) k<<1|1
#define lb lower_bound
#define orz cout<<"gzn ak ioi\n"
const int MAX=1e6+10;
const int MOD=1e9+7;
using namespace std;
inline char readchar() {
	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() {
// #define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int n,m,k;
int x[MAX],y[MAX];
inline double dis(int i,int j){
	int dx=x[i]-x[j],dy=y[i]-y[j];
	return double(sqrt(dx*dx+dy*dy));
}
int fa[MAX],mn[MAX],mx[MAX];
int fid(int x){return fa[x]==x?x:fa[x]=fid(fa[x]);}
bool check(double lim){
	for(int i=1;i<=k;i++){
		fa[i]=i;
		mn[i]=1e9;
		mx[i]=-1e9;
	}
	for(int i=1;i<=k;i++)
		for(int j=1;j<=k;j++)
			if(dis(i,j) < lim*2.0){
				int u=fid(i),v=fid(j);
				if(u!=v) fa[u]=v;
			}
	for(int i=1;i<=k;i++){
		int fu=fid(i);
		mn[fu]=min(mn[fu],y[i]);
		mx[fu]=max(mx[fu],y[i]);
	}
	for(int i=1;i<=k;i++)
		if(mn[i]<=2.0*lim&&m-mx[i]<=2.0*lim)
			return 0;
//	puts("");
	return 1;
}
signed main(){
	n=read(),m=read(),k=read();
	for(int i=1;i<=k;i++) x[i]=read(),y[i]=read();
	double l=0.0,r=1e6,ans=m/2.0,mid;
	while(l + 1e-7 < r){
		mid = (l+r)/2.0;
		if(check(mid)) l=ans=mid;
		else r=mid;
	}
	printf("%.10lf",ans);
	return 0;
}

T4

考场用时:\(0.5\) h

考场写了一个假的 dp,因为没有把 dp 初值设为 \(-inf\),导致不合法状态转移,我的式子设的是 \(dp_{i,j}\) 表示前 \(i\) 个数,最后一段是 \(j~i\) 的最大段数,这个 式子设的其实不是很妙,一是没有什么优化空间,而是转移时必须跑满。

而换一个式子,设 \(dp_{i,j}\) 表前 \(i\) 个数,分 \(j\) 段,最后一段的最小和。

这个转移时是跑不满的,所以可以过,当然也可以用线段树优化转移来获得更优复杂度。

#include<bits/stdc++.h>
#define ll long long
#define int long long
//#define ull unsigned long long
#define lc(k) k<<1
#define rc(k) k<<1|1
#define lb lower_bound
#define orz cout<<"gzn ak ioi\n"
const int MAX=4010;
const int MOD=1e9+7;
using namespace std;
inline char readchar() {
	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() {
#define readchar getchar
	int res = 0, f = 0;
	char ch = readchar();
	for(; !isdigit(ch); ch = readchar()) if(ch == '-') f = 1;
	for(; isdigit(ch);ch = readchar()) res = (res << 1) + (res << 3) + (ch ^ '0');
	return f ? -res : res;
}
inline void write(int x) {
    if(x<0){putchar('-');x=-x;}
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
int n,a[MAX],siz[MAX];
long long f[MAX][MAX],sum[MAX],qwq;
signed main(){
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read(),sum[i]=sum[i-1]+a[i];
		for(int j=0;j<=n;j++) f[i][j]=1e18;
	}
	for(int i=0;i<=n;i++) f[i][0]=-1e18;
	for(int i=1;i<=n;i++){
		for(int j=i-1;j>=0;--j){
			qwq=sum[i]-sum[j];
			int kai=(j==0?0:1); 
			for(int k=kai;k<=siz[j];k++){
				if(f[j][k]<qwq) if(f[i][k+1]==1e18) ++siz[i];
				if(f[j][k]<qwq) f[i][k+1]=min(f[i][k+1],qwq);
			}
		}
	}
	cout<<siz[n];
}

posted @ 2022-10-27 22:58  wapmhac  阅读(19)  评论(0编辑  收藏  举报