恩偶爱皮模拟尸体-32

水博客太快乐了

RT

考场

又是紧张刺激激动人心的CT报灵赛了。。。

开考先看题,看完三道题感觉没一道可做。。。
感觉凉了。。。

于是决定从 \(T1\) 开始看起。。。。
不会,直接大力线性筛。。。
发现好多无贡献的数也被计算了。。。
于是考虑优化,写了堆优化,两个大样例过了,然后最大的那个跑了将近 \(10s\) 。。。
不管了,先看 \(T2\) \(T3\) 发现都没啥思路,于是写了暴力考虑优化 \(T1\) ,把堆改成了队列,感觉应该会快很多,然而大样例还是跑了 \(3s\)\(4s\)。。。
但是感觉时间复杂度是正确的,常数也小的可怜。。。
不管了,就这样交吧。。。
重新看 \(T2\ T3\) ,深刻地认识到了我什么都不会的事实。。。
于是 \(T2\) 大力 \(xin\ team\)\(T3\) 直接骗 \(30pts\) 。。。
感觉冲后两题不如回来优化 \(T1\) 。。。(其实此时 \(T1\) 已经过了。。。。

最后也没有水出什么有用的东西。。。。

分数

预估 : \(t1\ 80pts\ +\ t2\ 20pts\ +\ t3\ 30pts\ =\ 130pts\)
实际 : \(t1\ 100pts\ +\ t2\ 24pts\ +\ t3\ 30pts\ =\ 154pts\)

震惊!!! \(t1\) 居然就这么过了???!!!
后来和巨佬 \(CYH\) 表达了我对 \(A\) 了这题的震惊,得知他本机最大样例不到 \(1s\) 就跑完了。。。是我电脑太卡了???

题解

A. Smooth

乍一看只会暴力,于是写了大力线性筛,发现线性筛的时候有很多数实际上对答案是没有贡献的,与是考虑优化,发现线性筛是将每一个找到的质数都存下来,用来筛之后的数,然而当质数大于 \(p_{b}\) 时,就已经不可能对答案有贡献了,所以只用前 \(b\) 个数筛即可,将筛到的数存到堆或队列里,堆带一个 \(\log\) 所以显然会 \(T\)
所以要用队列,用队列为了保证选数时的单调性,必须开 \(b\) 个队列,每次从这 \(b\) 个队列的队头中找一个最小值进行线性筛的操作即可。。。
时间复杂度 \(O(KB)\) ,显然可过。。。

code
#include<bits/stdc++.h>
using namespace std;
const int B=16, K=1e7+10;
const long long MAXN=1e18+5;
inline int read(){
	int f=1, x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
	return f*x;
}
int cnt, b, k, minn;
long long pri[B], u;
bool vis[100];
queue<long long> q[B];
int main(void){
	b=read(), k=read()-1;
	if(!k) { printf("1\n"); return 0; }
	for(int i=2; cnt<b; ++i){
		if(!vis[i]) pri[++cnt]=i;
		for(int j=1; j<=cnt&&i*pri[j]<100; ++j){
			vis[pri[j]*i]=1;
			if(i%pri[j]==0) break;
		}
	}
	for(int i=1; i<=cnt; ++i) q[i].push(pri[i]);
	while(k){
		minn=1;
		for(int i=2; i<=cnt; ++i)
			if(q[i].front()<q[minn].front()) minn=i;
		u=q[minn].front(); q[minn].pop();
		if(--k==0) { printf("%lld\n", u); return 0; }
		for(int i=1; i<=cnt&&pri[i]*u<MAXN; ++i){
			q[i].push(pri[i]*u);
			if(u%pri[i]==0) break;
		}
	}
	return 0;
}

B. Six

本场比赛最毒瘤的题。。。

巨佬 \(szs\) :大家应该都能看出来,这是一个简单的 \(dp\)
。。。。
考虑设计状态,显然每个数可以被看作是一个由若干质数组成的集合,既然题中已经告诉了我们每个数最多有 \(6\) 个质因子,因此可以考虑状压。。。
设质因子的状态为 \(S\)
若新加入一个数,考虑目前是什么情况它才可以插入。。。
发现当且仅当不存在一个数对,使得当前数与这两个数均含有相同的质因子,因此设是否存在一个同时包含某些质因子的数对的状态为 \(T\) 。。。

转移很麻烦,直接看代码吧。。。

code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long
#define fi first
#define se second
const int N=1e6+10, M=3e7+10, mod=1e9+7;
inline ll read(){
	int f=1, x=0; char ch=getchar();
	while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); }
	while(isdigit(ch)) { x=x*10+ch-48; ch=getchar(); }
	return f*x;
}
ll n;
ll stk[N], p[7], cnt[N];
bool vis[M];
int top1, ul1[7][7], f[1<<7], top;
map<pair<int, int > , ll> mp;
int ex[10], top2;
void pre_work(){
	ll ul=n, nn=sqrt(n);
	for(ll i=2; ul!=1&&i<=nn; ++i)
		if(ul%i==0){
			p[++top1]=i;
			while(ul%i==0) ul/=i;
		}
	if(ul!=1) p[++top1]=ul; ul=0;
	for(int i=2; i<=nn; ++i)
		if(n%i==0){
			stk[++top]=i;
			if(i*i!=n) stk[++top]=n/i;
		}
	stk[++top]=n;
	for(int i=1; i<=top; ++i){
		for(int j=1; j<=top1; ++j)
			if(stk[i]%p[j]==0) ul|=1<<(j-1);
		++cnt[ul]; ul=0;
	}
	for(int i=1; i<=top1; ++i) for(int j=i; j<=top1; ++j)
		ul1[i][j]=ul1[j][i]=ul++;
	for(int i=1; i<1<<top1; ++i){
		top2=0;
		for(int j=1; j<=top1; ++j)
			if(i&(1<<(j-1))) ex[++top2]=j;
		for(int j=1; j<=top2; ++j) for(int k=j; k<=top2; ++k)
			f[i]|=(1<<ul1[ex[j]][ex[k]]);
	}
}
ll dfs(pair<int, int > u){
	if(mp[u]) return mp[u]; int ul;
	for(int i=1; i<1<<top1; ++i){
		if(f[i]&u.se) continue;	ul=u.se;
		for(int j=1; j<=top1; ++j){
			if((i&(1<<(j-1)))==0) continue;
			for(int k=1; k<=top1; ++k)
				if(u.fi&(1<<(k-1))) ul|=(1<<ul1[j][k]);
		}
		mp[u]+=((dfs(make_pair(u.fi|i, ul))+1)*cnt[i])%mod;
		mp[u]%=mod;
	}
	return mp[u];
}
signed main(void){
	n=read(); pre_work();
	printf("%lld\n", dfs(make_pair(0, 0)));
	return 0;
}

C. Walker

首先很显然,若确定两个点,则一定可以确定一组解。。。(可以使用高斯消元,也可以直接算出来。。。
若要判断这组解是否合法,则显然可以 \(O(n)\) 判断。。。
若要枚举每一对点对,则显然会 \(T\) ,所以可以考虑随机化优化,因为题中告知,至少有一半的点是正确的,所以一次找到正确答案的概率是 \(\frac{1}{4}\) ,这个概率显然大的可怕,随便随几组数据就能找到。。。(如果 \(RP\) 足够高可以尝试只随一组数据。。。

code
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const double eps=1e-6;
int n;
double x[N], y[N], x1[N], y10086[N];
double a[10][10], b[10];
inline void gauss(){
	for(int i=1; i<=4; ++i){
		int id=0; double ul;
		for(int j=i; j<=4; ++j)
			if(fabs(a[j][i])>fabs(a[id][i])) id=j;
		ul=a[id][i]; b[id]/=ul;
		for(int j=1; j<=4; ++j) a[id][j]/=ul;
		for(int j=1; j<=4; ++j) swap(a[id][j], a[i][j]); swap(b[id], b[i]);
		for(int j=1; j<=4; ++j){
			if(i==j) continue;
			ul=a[j][i]; b[j]-=ul*b[i];
			for(int k=i; k<=4; ++k)
				a[j][k]-=ul*a[i][k];
		}
	}
}
inline bool check(){
	double xx, yy; int num=0;
	for(int i=1; i<=n; ++i){
		xx=x[i]*b[1]-y[i]*b[2]+b[3]; yy=y[i]*b[1]+x[i]*b[2]+b[4];
		if(fabs(xx-x1[i])<=eps&&fabs(yy-y10086[i])<=eps) ++num;
	}
	return num>=((n+1)>>1);
}
inline void get_ans(){
	double an, scale, dx, dy;
	scale=sqrt(b[1]*b[1]+b[2]*b[2]);
	an=acos(b[1]/scale);
	if(fabs(sin(an)*scale-b[2])>eps) an=-an;
	dx=b[3], dy=b[4];
	printf("%.10lf\n%.10lf\n", an, scale);
	printf("%.10lf %.10lf\n", dx, dy);
}
int main(void){
	scanf("%d", &n); srand(time(0));
	for(int i=1; i<=n; ++i)
		scanf("%lf%lf%lf%lf", &x[i], &y[i], &x1[i], &y10086[i]);
	for(int i=1; i; ++i){
		int a1=rand()%n+1, b1=rand()%n+1;
		if(a1==b1) { --i; continue; }
		a[1][1]=x[a1], a[1][2]=-y[a1], a[1][3]=1, a[1][4]=0; b[1]=x1[a1];
		a[2][1]=y[a1], a[2][2]=x[a1], a[2][3]=0, a[2][4]=1; b[2]=y10086[a1];
		a[3][1]=x[b1], a[3][2]=-y[b1], a[3][3]=1, a[3][4]=0; b[3]=x1[b1];
		a[4][1]=y[b1], a[4][2]=x[b1], a[4][3]=0, a[4][4]=1; b[4]=y10086[b1];
		gauss(); if(check()) { get_ans(); return 0; }
	}
	return 0;
}
posted @ 2021-08-07 20:19  Cyber_Tree  阅读(52)  评论(2编辑  收藏  举报