暑假集训D20 2023.8.15 contest E NWERC 2021

A.Access Denied

题意:给出系统密码比对的程序和每条指令所耗费的时间,你需要通过程序返回的执行时间来破解出正确的密码.

Solution

由题目检查密码的程序.可以先猜长度再猜每个字符.长度错误会耗费 5ms .直到返回的时间不是 5ms 说明长度猜对了.
然后猜每个字符.根据判断的程序.首先判断长度花费了 4ms.
然后每次 for 循环都要花费 5ms (赋值或i++花费 1ms ,比较花费 3ms ,for分支花费 1ms )
进入循环后,判断字符时,如果不等于则花费 5ms+4ms ,如果相等花费 5ms+5ms ,不妨假设前 k 个字符相等,第 k+1 个字符不等,那么花费时间就是 4+9k+10ms.
每次枚举每个位置的字母即可.返回的时间 x ,代表下标在 x/91 上的字母出错了,枚举即可.
时间复杂度 O(2n)

#include<bits/stdc++.h>

using namespace std;
#define  pb push_back
vector<char> p;
int check(string t)
{
	cout<<t<<endl;
	string str;
	cin>>str;
	cin>>str;
	if(str=="GRANTED")
	{
		exit(0);
	}
	int x;
	scanf(" (%d",&x);
	// cout<<"x:"<<x<<endl;
	cin>>str;
	return (x/9) -1;
}
int main()
{
	string s = "a";
	int len =1;
	for(int i= 'a';i<='z';i++)
		p.pb(i);
	for(int i= 'A';i<='Z';i++)
		p.pb(i);
	for(int i= '0';i<='9';i++)
		p.pb(i);
	// for(char j:p)
	// {
	// 	cout<<j<<endl;
	// }
	int x;
	while(1)
	{
		cout<<s<<endl;
		string str;
		cin>>str;
		// cout<<str<<' ';
		cin>>str;
		// cout<<str<<' ';

		if(str=="GRANTED")exit(0);
		
		scanf(" (%d",&x);
		// cout<<x<<' ';
		cin>>str;
		// cout<<str<<'\n';

		if(x!=5)break;
		len++;
		s+="a";
	}
	// cout<<len<<endl;
	int i = x/9 - 1;
	// cout<<i<<endl;
	for(;i<len;)
	{
		for(char j :p)
		{
			// cout<<"j:"<<j<<endl;
			s[i] = (char)j;
			int temp = check(s);
			// cout<<"temp:"<<temp<<endl;
			if(temp!=i)
			{
				i = temp;
				break;
			}
		}
	}

	return 0;
}

J.Jet Set

题意:一个人沿着环球航行,给出每个景点的经纬度,这个人从第一个点出发,依次走到最后一个点,再从最后一个点回到起点.注意每两个点之间,这个人只会走近的那一条路.问这个人能否完成环球航行?(所有的经度都被走过)

Solution
首先由于度数是 180180 ,负数不好处理,将他们偏移到 0360 .另外,如果

考虑差分,对于两个点的经度 l 和经度 r ,如果从 lr 那么分为 rl 大于180度和小于180度的情况.如果小于很简单,直接让 lr 之间的数 +1 即可(采用差分很容易实现),如果大于,则是 0l,r360 的数 +1 .如果他们两个正好相差 180 度,也就是正好相差一个半球,那么若这一边没有走过,就走这边,如果这边走过了,就走另一边个半球,否则重复的走会使得原本能恰好走完的路径导致最后有一边没有走.

另外还有一种情况,比如 017917911801790,这样虽然走完了 1800,1180,但是 $0\sim1中间的没有走(如0.5),直接用差分的话,只能检测到 0,1 都走了,检测不出来 0.5 有没有走,简便的解决方法是把所有度数变为原来的两倍.最后得结果时除以 2 即可.

时间复杂度 O(n)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;

int a[N],x[N],y[N];
int m = 720;
void add(int l,int r)
{
	a[l]++;
	a[r+1]--;
}
int getsum(int l)
{
	int res = 0;
	for(int i = 0;i<=l;i++)
		res+=a[i];
	return res;
}
int check(int l,int r)
{
	int res = 0;
	for(int i = 0;i<=r;i++)
	{
		res+=a[i];
		if(res==0&&i>=l)
		{
			return 0;
		}
	}
	return 1;
}
void solve(int p,int q)
{
	int a = p,b = q;
	if(a>b)swap(a,b);
	if(b-a>m/2)
	{
		add(0,a),add(b,m);
	}
	else if(b-a==m/2)
	{
		if(!check(a,b))//如果他们俩差了半个半球,并且一边没有走过,就走这边,如果这边走过了,就走另一边个半球
		{
			add(a,b);
		}
		else add(0,a),add(b,m);
	}
	else add(a,b);
}
signed main(int argc, char const *argv[])
{
	int n;
	cin>>n;
	for(int i= 1;i<=n;i++)
	{
		cin>>x[i]>>y[i];
		y[i]= y[i]*2+360;
	}
	y[n+1] = y[1];
	for(int i= 2;i<=n+1;i++)
	{
		solve(y[i-1],y[i]);
	}

	int sum = 0;
	for(int i = 0;i<=720;i++)
	{
		sum+=a[i];
		if(sum==0)
		{
			cout<<"no "<<fixed<<setprecision(1)<<(double)(i-360)/2;
			exit(0);
		}
	}
	cout<<"yes";
	return 0;
}

I.IXth Problem

给定一定个数的罗马字母,问能组合出来最少的罗马数字的个数是多少?(每个字母都必须用到,给出组合的方法和每种组合方法的个数.可能有多种组合方法,给出任意一种合法解即可)

Solution
考虑二分答案.那么问题转化成了给定整数 n ,要组合出来 n 个罗马数字最多能用多少个罗马字母.
那么只需要对 n 个组往里面依次装填罗马字母 M,D,C,L,X,V,I 即可.按如下规则填入:
首先三个三个填入每一组.如果不够了,就用该字母和下一个字母组合起来填入,比如 M 不够三个一组填完,就用 CM 填.
如果可以用完所有字母,那么就是合法解.
当数量很大时,可以通过给各组分相同的分法来加速这一过程.
时间复杂度 O(logn)

L.Lucky Shirt

n 件T恤自上而下放在衣柜里,每天从衣柜中最上面取出一件T恤穿,每天晚上穿完后放到洗衣篮里面.这个人要洗 k 轮衣服(只洗洗衣篮里的衣服,今天穿的衣服也会洗),每次洗衣服的间隔是完全均匀随机的(也即第 j 天随机洗前 lj 件),洗完衣服后随机地放回衣柜最顶部.已知幸运T恤的初始位置是 i ,洗完 k 轮衣服后,幸运T恤的期望位置是多少?

Solution

如果这 k 次每次都选的前 1i1 的某个位置,那么幸运T恤的最终位置还是 i ,概率 p=(i1n)k
如果这 k 次选的位置存在大于等于 i 的情况,设 k 次洗衣服最大选取的位置是 M ,则最后的位置期望是 (M+1)/2.要求最大位置是 M 的概率并不好求,然而可以方便地求出最大位置小于 M 的概率,即 p1=(M1n)k ,而最大位置小于 M+1 的概率为 p2=(M+11n)k , 最大位置等于 M 的概率就是最大位置小于 M+1 的概率减去最大位置小于 M 的概率即 p2p1 .
因此可以按照最大位置来分.当最大位置小于 i 时,期望位置 ExpPositionMi .当最大位置大于等于 i 时,期望位置 ExpPositionM(M+1)/2 ,最大位置为 a 时,概率 pa=(a+11n)k(a1n)k .
那么结果就是 a=1npaExpPositiona

时间复杂度 O(n)

#include<bits/stdc++.h>

using namespace std;
double getlessp(int M,int n,int k)//calc for k circle, P(MaxPosition < M)
{
	return pow((M-1)*1.0/n,k);
}
double getp(int M,int n,int k)//calc for k circle, P(MaxPosition = M)
{
	return getlessp(M+1,n,k)-getlessp(M,n,k);
}

signed main()
{
	double n,i,k;
	cin>>n>>i>>k;
	double res = 0;
	for(int m = 1;m <= n;m++)
	{
		double exp_position;
		if(m<i)
			exp_position = i;
		else exp_position = (m+1)/2.0;
		res+=exp_position*getp(m,n,k);
	}
	cout<<fixed<<setprecision(10)<<res;
	return 0;
}


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   Rainy_L  阅读(67)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示