暑假集训第4天的考试(2018.7.7)

很多的东西用法不知道

像2维字符串怎么输入

后来知道了:

字符串数组(2维字符数组)不能直接输入

(最好增加一个字符串,每次输入这个,再把它存到字符串数组中去,也可以char s[][];scanf("%s",%s[i])

字符串不能初始化0,新定义的字符串原本就是空的(像s=0)

题1:number

题⽬描述
给定⼀个1~n的排列,每⼀次可以对该排列进⾏这样的操作:
从排列中任意拿出⼀个数,放在该序列的最前⾯。
问⾄少经过多少次操作,可以使该排列变为123......n-1n
输⼊格式
输⼊包含多组数据。
第⼀⾏⼀个整数TT<=10),表⽰数据组数。
对于每组数据,第⼀⾏⼀个整数n表⽰排列的长度,接下来⼀⾏n个数表⽰
这个排列。
输出格式
对于每组数据,输出⼀个整数,表⽰最少经过⼏次操作可以恢复正常顺序。
样例输⼊
2
4
4 1 2 3
5

1 2 3 4 5

样例输出
3
0
样例说明
对于50%的数据
对于第⼀组数据,操作顺序为:
(4,1,2,3) (3,4,1,2) (2,3,4,1) (1,2,3,4)
对于第⼆组数据,已经是正常的顺序所以不需要任何操作了。
数据范围
对于50%的数据 n ≤ 10
对于80%的数据 n ≤ 1000
对于100%的数据 n ≤ 100000

。。。

题目一定要看仔细

结论不要片面

从大往小的位置检查

因为从大的开始确定

只要保持大的几个连续的确定就行了

(而我片面的认为一定要在最前面)

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
	int n;
	cin>>n;
	int a[2010]={};
	double F[5010]={},f[5010]={};
	for(int i=1;i<=n;i++)
	  cin>>a[i];
	sort(a+1,a+1+n);
	double  g=n*(n-1)/2;
	for(int i=1;i<n;i++)
	  for(int o=i+1;o<=n;o++)
	    f[a[o]-a[i]]+=double(1)/g;
	int mx=a[n]-a[1];
	for(int i=1;i<=mx;i++)
	  for(int o=1;o<=mx;o++)
	    F[i+o]+=f[i]*f[o];
	for(int i=1;i<=mx;i++)
	  F[i]+=F[i-1];
	double ans=0;
	for(int i=1;i<=mx;i++)
	    ans+=F[i-1]*f[i];	  
	printf("%.4lf",ans);
	fclose(stdin);
    fclose(stdout);
	return 0;
}

题2:sort

题⽬描述
给定 n 个由⼩写字母组成的字符串,请你求出⼀个字母表顺序,使得这 n

个字符串是按照字典序升序排列的,数据保证存在合法的字母表顺序。

多个解按字典需最大
输⼊格式
第⼀⾏⼀个整数 n
接下来 n ⾏,每⾏⼀个字符串。
输出格式
⼀⾏,⼀个 a z 各出现⼀次的字符串,表⽰字母表顺序 。
样例输⼊
10
petr
egor
endagorion
feferivan
ilovetanyaromanova
kostka
dmitriyh
maratsnowbear
bredorjaguarturnik
cgyforever
样例输出

aghjlnopefikdmbcqrstuvwxyz
数据范围
对于30%的数据 n<=100
对于100%的数据 n<=1000,字符串长度<=1000

我之前太钻牛角尖了

非要递归求不同的

用spfa求还要用万能节点

同时题意理解有些偏差

以为如果确定的不满26个字符还要

按字典序吧没有的补上去

好的解法是拓扑排序

代码:

#include<bits/stdc++.h>
using namespace std;
const int dd=100010;
int e[dd],next[dd],link[dd],top=0;
char str[dd]; 
int cs[200]={};
inline void into(int xx,int yy){e[++top]=yy,next[top]=link[xx],link[xx]=top;} 
int main()
{
	int n;
	cin>>n;
	string s[1010];
	for(int i=1;i<=n;i++)
		scanf("%s",&s[i]);
	for(int i=1;i<n;i++)
	{
		int pd=0;
		int l=min(s[i].size(),s[i+1].size());
		for(int o=0;o<l;o++)
		{
			if(s[i][o]!=s[i+1][o]) 
			{
				pd=1;
				into(s[i][o],s[i+1][o]);
				cs[s[i+1][o]]++;
				break;
			}
		}
		if(!pd&&s[i].size()>s[i+1].size()) 
		{
			cout<<"Impossible";
			return 0;
		}
	}
	queue<int>q;
	for(int i='a';i<='z';i++)
	  if(!cs[i])
	    q.push(i);
	string ans;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		ans+=(char)u;
		for(int i=link[u];i;i=next[i])
		{
			if(!--cs[e[i]])
			{
				q.push(e[i]);
			}
		}
	}
	if(ans.size()!=26) 	cout<<"Impossible";
	else cout<<ans;   
	return 0;
} 
题3:seq 题⽬描述
给定⼀个长度为n的序列, AB 随机从序列中拿⼀个数(放回)谁的⼤算
谁赢,⽐赛三局两胜,已知AB的⽐赛结果为前两局A胜,第三局B胜。求这
三局B取得数的和⽐A取得数的和⼤的概率。
输⼊格式
第⼀⾏⼀个整数n,⼀⾏n个正整数表⽰序列中的每⼀个数ai
输出格式
输出⼀个实数,保留四位⼩数。

样例输⼊
3
1 2 10
样例输出
0.0741
数据范围
对于20%的数据 n<=20
对于40%的数据 n<=200

对于100%的数据 n<=20001<=ai<=5000

这题正解跟dp较像

先求出相差x的概率f[]

求出A前两次大B的概率F[i+o]=f[i]*f[o]

求出A前两次大B的前缀和F[x]+=F[x-1]

枚举f

计算f[]>F[]的所有

就相当ans+=f[i]*f[i-1]

代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
	int n;
	cin>>n;
	int a[2010]={};
	double F[5010]={},f[5010]={};
	for(int i=1;i<=n;i++)
	  cin>>a[i];
	sort(a+1,a+1+n);
	double  g=n*(n-1)/2;
	for(int i=1;i<n;i++)
	  for(int o=i+1;o<=n;o++)
	    f[a[o]-a[i]]+=double(1)/g;
	int mx=a[n]-a[1];
	for(int i=1;i<=mx;i++)
	  for(int o=1;o<=mx;o++)
	    F[i+o]+=f[i]*f[o];
	for(int i=1;i<=mx;i++)
	  F[i]+=F[i-1];
	double ans=0;
	for(int i=1;i<=mx;i++)
	    ans+=F[i-1]*f[i];	  
	printf("%.4lf",ans);
	fclose(stdin);
    fclose(stdout);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值