传送门
D题
题意:波浪数组满足四个条件:1、至少两个元素。2、奇数位的数都相等。3、偶数位的数都相等。4、奇数位和偶数位的数不相等。给你一个数组(数组中元素不大于c),你要从中找出波浪数组的最大长度。(保证波浪数组是该数组的一部分就行,就是可以在数组中任意按顺序挑选,使之满足波浪数组的条件)
这个题可以用动态规划(dp)来解。首先了解一下什么是dp。
- 将一个复杂的问题分解成若干个子问题,通过综合子问题的最优解来得到原问题的最优解
- 动态规划会将每个求解过的子问题的解记录下来,这样下一次碰到同样的子问题时,就可以直接使用之前记录的结果,而不是重复计算
- 可以用递归或者递推的写法实现,递归的写法又叫记忆化搜索
- 重叠子问题:如果一个问题可以被分解成若干个子问题,且这些子问题会重复出现,就称这个问题拥有重叠子问题。 一个问题必须拥有重叠子问题,才能用动态规划去解决。
首先我们来构造一个波浪数组,比如:1 2 1 2 1 2 1 2
很容易就发现当奇数位是1,偶数位是2的时候,波浪数组的排列一定是1后面是2,2后面是1,再1后面是2,2后面是1...
于是子问题就成了,当1出现的时候我们去找后面的2,并且ans++,当2出现的时候我们去找1,ans++...(因为分开来看,你找的只是波浪数组中的奇数位和偶数位的数字而已)
那么,如何来记录1 2 1 2 1 2 1 2这样的数组呢?
可以用一个二维数组巧妙地利用这两个相关的数组来记录他们出现的次数。
因为i的后面一定是j,j的后面一定是i.故dp[i][j]=dp[j][i]+1,dp[j][i]=dp[i][j]+1.这个计数方式妙处在于dp[i][j]中i是目前正在遍历的数字,而j是添加的后缀用来辨认下一个j来计数的。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
int a[maxn];
int dp[105][105];
int main()
{
freopen("input.txt","r",stdin);
int n,c;
cin>>n>>c;
for(int i=0;i<n;i++) cin>>a[i];
int maxlen=0;
for(int i=0;i<n;i++)//所有元素
{
for(int j=1;j<c;j++)//从1到c遍历
{
dp[a[i]][j]=dp[j][a[i]]+1;
if(a[i]==j) continue;
maxlen=max(maxlen,dp[a[i]][j]);
}
}
cout<<maxlen<<endl;
return 0;
}
F题
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
int a[maxn],b[maxn],dis[maxn],vis[maxn];
int main()
{
int len;
while(cin>>len)
{
string s;
cin>>s;
int al=0,vl=0,il=0,nl=0;
for(int i=0;i<len;i++)
{
if(s[i]=='a') al++;
if(s[i]=='v') vl++;
if(s[i]=='i') il++;
if(s[i]=='n') nl++;
}
int num=al*vl*il*nl;
int den=len*len*len*len;
int yue=__gcd(num,den);
cout<<num/yue<<"/"<<den/yue<<endl;
}
return 0;
}
G题
做不出这道题的童鞋相信都卡在了这个坑里。
all the cars running in the north-south direction wait the same amount of integral time so that no two cars bump.
去掉定语后是:all the cars wait the same time. 所有汽车等待时间相同。
这句话的意思是:所有南北方向上的汽车要等待相同的时间,以至于没有两辆汽车相撞。
这句话的关键是所有汽车等待时间相同,要么全都是5min,要么全都是10min,不能这辆汽车等1min、那辆汽车等2min的。
暴力枚举即可。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
int a[maxn],b[maxn],dis[maxn];
int main()
{
int n,m;
while(cin>>n>>m)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(dis,0,sizeof(dis));
for(int i=0;i<n;i++)
{
cin>>a[i];
dis[a[i]]=1;
}
for(int i=0;i<m;i++) cin>>b[i];
int ans;
for(int i=0;i<1001;i++)
{
int flag=0;
for(int j=0;j<m;j++)
{
if(dis[b[j]+i])
{
flag=1;
break;
}
}
if(!flag)
{
ans=i;
break;
}
}
cout<<ans<<endl;
}
return 0;
}
H题
题解:
题意:
给你一段区间1-n,可以从这个这个区间里找到一个点,记为r,从1-r找到一个点,记为l,问通过这个方法找任意两个区间的概率。
解答:
求算相交的概率,就是求算1减去不相交的概率,因为相交的概率并不好求,所以可以先转化一下角度。
根据古典概型理论,全部的情况为n*n
不相交的所有情况就是左区间的右端点小于右区间的左端点的所有位置,即等差数列n*(n-1)/2;
所以所求概率为1 - ((n*(n-1)) / 2 / n*n);
题目要求答案是p/q(mod 1e9+7)
因为运算要进行取模,所以除法要变成乘以其逆元,求逆元可以用费马小定理,a的逆元为a^(mod-2).
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll ksm(ll a,ll n)
{
ll res=1;
while(n)
{
if(n&1) res=res*a%mod;
a=a*a%mod;
n>>=1;
}
return res;
}
int main()
{
ll n;
while(cin>>n)
{
cout<<(n+1)*ksm(n*2,mod-2)%mod<<endl;
}
return 0;
}
I题
题意概括:给你n个数(小数点后面保留三位),现在要把这些三位数全都四舍五入变成两位数。问这些数变成两位全都变成两位数之后,与改变位数之前的差值是多少。
解题思路:字符串输入,用str表示字符串的最后一位、ans统计每个数与改变位数之前的差值的1000倍,即小数点后面的第三位。如果str变成数字后小于5,说明四舍五入后会丢失这个数ans-=(str-'0').如果str变成数字后大于等于5,说明四舍五入后ans增加(10-(str-'0')).输出的时候ans再除以1000.
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
int main()
{
int n;
while(cin>>n)
{
int ans=0;
for(int i=0;i<n;i++)
{
string s;
cin>>s;
int len=s.length();
char str=s[len-1];
if((str-'0')<5) ans-=(str-'0');
else ans+=(10-(str-'0'));
}
if(ans<0) cout<<"-";
ans=abs(ans);
float y=ans/1000.0;
printf("%.3f\n",y);
}
return 0;
}
J题
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
const int maxn=1e4+10;
typedef long long ll;
int a[maxn];
ll gcm(ll a,ll b)
{
ll ans=__gcd(a,b);
ans=a*b/ans;
return ans;
}
int main()
{
ll n,m;
while(cin>>n>>m)
{
for(int i=0;i<n;i++) cin>>a[i];
ll temp=1;
for(int i=0;i<n;i++)
{
temp=gcm(a[i],temp);
}
ll temp2=0;
for(int i=0;i<n;i++) temp2+=(temp/a[i]);
if(m%temp2==0)
{
cout<<"Yes"<<endl;
ll c=m/temp2;
cout<<temp/a[0]*c;
for(int i=1;i<n;i++) cout<<" "<<temp/a[i]*c;
cout<<endl;
}
else cout<<"No"<<endl;
}
return 0;
}
K题
没想到竟然PE了,少输换行符竟然还会错,还是养成输换行符的习惯吧。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdio>
using namespace std;
typedef long long ll;
int main()
{
int x,y;
cin>>x>>y;
int num=(x+y)/2;
printf("%d\n",num*(num-y));
return 0;
}