题目链接
前言
这次比赛打地太失败了,一定要吸取教训,我们队伍三个人都在开不同的题,这也算是一次崭新的尝试。不过事实证明这样的方法在我们这样水平的队伍里还是行不通的。结果就是开的题太多但是过的题目不多,很多题目都是一个人来写的话就会造成一种情况就是难免会有一些点想不透。需要引以为戒。
B Boxes
思路
这道题当时是我负责写的,不过很遗憾的是我考虑的情况还是欠缺了点。题目总共有两种情况,一种是直接打开所有的盒子,另一种才是先获得提示然后再打开一定数量的盒子,然后两者比较取较小值。而我只考虑到了第二种情况,反而是第一种简单的情况一直没有在我考虑范围内,所以一直WA。至于第二种方法推出的公式:C+∑Wi(1-1/(2n-i))其实容易得出,不会推的话直接写出4,5的情况也能得到这个规律。
附上代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define lmax 1000
#define pi 3.141592653589793238462643383279
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef long double type;
double w[100009];
int main()
{
int n;
double c;
scanf("%d%lf",&n,&c);
double sum=0;
for(int i=1;i<=n;i++)
{
scanf("%lf",&w[i]);
sum+=w[i];
}
sort(w+1,w+n+1);
double res=0;
for(int i=1;i<=n;i++)
{
res=res/2+w[i];
}
printf("%.8lf\n",sum+min(0.0,c-res));
return 0;
}
/*
20 45
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
*/
D Double Strings
思路
并没有做出这道题,后来才知道是可以用dp来做的,可能还是练习这方面的题练习地太少了,这里推荐一篇博客,思路还是很清晰的,当然,好像还有其他的方法。
链接
大佬的代码
#include <iostream>
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pi 3.141592653589793238462643383279
using namespace std;
typedef long long ll;
const int N = 5e3 + 10;
const int M = 1e9 + 7;
const double eps = 1e-5;
char s1[N], s2[N];
int dp1[N][N];
int dp2[N][N];
int main()
{
scanf("%s%s",s1+1,s2+1);
int n, m;
n = strlen(s1 + 1), m = strlen(s2 + 1);
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(s1[i] == s2[j])
{
dp1[i][j]++;
dp1[i][j] = (dp1[i][j] + dp1[i - 1][j - 1]) % M;
}
dp2[i][j]++;
dp1[i][j] = (dp1[i][j] + dp1[i][j - 1]) % M;
dp1[i][j] = (dp1[i][j] + dp1[i - 1][j]) % M;
dp1[i][j] = (dp1[i][j] - dp1[i - 1][j - 1]) % M;
dp2[i][j] = (dp2[i][j] + dp2[i][j - 1]) % M;
dp2[i][j] = (dp2[i][j] + dp2[i - 1][j]) % M;
}
}
ll ans = 0;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
if(s1[i] < s2[j])
{
ans = (ans + 1ll * (dp1[i - 1][j - 1] + 1) * (dp2[n - i][m - j] + 1) % M) % M;
}
}
}
printf("%lld",(ans+M)%M);
}
H Holding Two
签到题,思路就不说了,直接看代码吧。
附上代码
#include <bits/stdc++.h>
using namespace std;
int f[1001][1001];
int main()
{
cin.sync_with_stdio(0);
cin.tie(0);
for(int i = 1;i <= 1000;i++)
{
for(int j = 1;j <= 500;j++)
{
if(i&1)
{
if(j&1)
{
f[i][2*j-1] = 1;
f[i][2*j] = 1;
}
else
{
f[i][2*j-1] = 0;
f[i][2*j] = 0;
}
}
else
{
if(j&1)
{
f[i][2*j-1] = 0;
f[i][2*j] = 0;
}
else
{
f[i][2*j-1] = 1;
f[i][2*j] = 1;
}
}
}
}
int n,m;
cin >> n >> m;
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= m;j++)
{
cout << f[i][j];
}
cout << endl;
}
return 0;
}
K King of Range
思路
当时这道题没有做出来,后来看到题解之后发现原来可以用单调队列来做,其实到最后一个半小时的时候我们已经想到了估计可以用这种思路,不过一方面我们之前并没有写过相关的题目,另一方面对于单调队列用的也不是很熟练,因此最终并没有将这道题给啃下来。
基本就是思路就是维护两个单调队列,其中一个递增序列,队首维护最小值;另一个递减序列,队首维护最大值,每次弹出两个队列中队首靠前的那一个,直到极差<=k。
附上代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pi 3.141592653589793238462643383279
#define eps 1e-7
using namespace std;
typedef long long ll;
typedef int type;
const int maxn=1e5+10;
int a[maxn];
int main()
{
int n,m,k;
scanf("%d%d",&n,&m);
for (int i= 1;i<=n;i++)
scanf("%d",&a[i]);
while(m--)
{
cin>>k;
deque<int> qMax,qMin;//双端队列定义两个单调队列
ll ans=0;
for(int l=1,r=1;r<=n;++r) //保证整个队列要单调,初始时l,r都是1
{
while(qMax.size()&&a[qMax.back()]<a[r])//只要qmax最尾部的数小于a[r],就不断弹出
qMax.pop_back();
qMax.push_back(r);//然后将r放进去
while(qMin.size()&&a[qMin.back()]>a[r])
qMin.pop_back();
qMin.push_back(r);//最小队列的维护方式和最大队列是一样的。
while(a[qMax.front()]-a[qMin.front()]>k)
{
ans+=(ll)n-r+1;//只要包含了l到r的区间都成立
l++;
if(qMax.front()<l)//向右移动l,如果队列最大值的编号小于l就弹出
qMax.pop_front();
if(qMin.front()<l)
qMin.pop_front();
}
}
printf("%lld\n",ans);
}
}