值得纪念的一场比赛,所以写个游记。
8:00有一场比赛,早早地做好了准备,心中燃放着一股怒火。但是,不知道是网站崩溃了,还是家里的网络崩溃了,本蒟蒻迟迟进不去Atcoder,而班级里的好多人都成功进去了并告诉我8:10才开始。
结果从8:00一直等待响应到8:08,才加载出比赛的页面。在这个期间,我崩溃了两次。
比赛一开始就打开A题。刚开始以为是一道数学题,可在看完数据范围之后一顿暴力枚举轻松切掉。
但是毕竟A题总是很水,所以我根本没有增强信心。
接着打开B题,发现是一道模拟题。于是,我让100每次乘1.01,直到到达 X X X的时候停止,并记录下次数。
惊人地发现前两题花了15分钟,到底是我太菜还是网络太菜?
接着打开C题,发现难度飙升——dp? 贪心?两次惨痛的WA告诉了我这都不是。
之所以我没有用正解暴力,是因为我没有看到一个重要东西: 1 ≤ a 1 ≤ a 2 ≤ a 3 ≤ … … a n ≤ m 1≤a_1≤a_2≤a_3≤……a_n≤m 1≤a1≤a2≤a3≤……an≤m。
所以枚举 a a a数组并不是全排列。那个时候脑子瓦特的我以为这是全排列,时间复杂度 O ( n ! q ) O(n!q) O(n!q),会超时!
然后我打了一个全排列的暴力,连样例都过不了。于是,我debug了好久好久,就是没看到那一句话,然后没有崩溃而是自闭了。
但是当我想到一年前一场AT比赛,我过了A, B, D, E题时,我才振作起来打开D和E题。
打开D题一看,什么东西啊?神仙题吗?
那时的本蒟蒻认为,本题中的 x x x与 a , b , c a,b,c a,b,c没有任何关系,所以可能是一个二分。
结果往二分方向苦想无果,又看了一眼数据范围—— a ≤ 1 0 6 a≤10^6 a≤106
所以说,本蒟蒻傻傻的以为这题是要弄一个 O ( a ) O(a) O(a)时间复杂度的算法。而这种算法一定就是枚举 x x x,其中 x ≤ m i n ( a , n ) x≤min(a,n) x≤min(a,n),这个就是正解啦!
于是我要交了,等待我的仍然是WA。
接着,我怀着焦急的心理打开QQ,发现班级里一位神仙已经秒切了A,B,C,D题。
心态真得炸了!心态真得炸了!心态真得炸了!
那怎么办?拼啊!
我关掉QQ,闭上眼睛,然后盯着第三题的题面
…………
我貌似看到了一行字: 1 ≤ a 1 ≤ a 2 ≤ a 3 ≤ … … a n ≤ m 1≤a_1≤a_2≤a_3≤……a_n≤m 1≤a1≤a2≤a3≤……an≤m。
要个毛全排列啊,TM直接组合计数不久TM可以了吗,我TM怎么这么笨啊!
然后我以为会切掉这题,不料命运多舛,我又WA了。但是没事,我发现组合计数写错了,改一改加个break即可。
距离比赛结束78分钟,我终于AC了前三题。
然后到D题。
有一个很明显的东西,就是含有 x x x的分数的分母都是 b b b。
f l o o r ( a × x / b ) − a × f l o o r ( x / b ) floor(a×x/b)-a×floor(x/b) floor(a×x/b)−a×floor(x/b)。
找规律无果。接着我想到 a ≤ 1 0 6 a≤10^6 a≤106并不是为了让你搞有关 O ( a ) O(a) O(a)的算法,而是不让答案溢出。
通过观察,我猛然发现——贪心?!?!?!
当 x = b − 1 x=b-1 x=b−1的时候,原来的式子总是最大的。
但是有 n n n的限制,所以这里 x = m i n ( n , b − 1 ) x=min(n,b-1) x=min(n,b−1)。
这个推理过程虽然不严谨,但是看到比赛将在2分钟后结束的时候,我果断地开始打代码。
键盘微凉 鼠标微凉
指尖流淌 代码千行
距离比赛结束还有32秒~
拉到最下面,提交!
2/32
9/32
18/32
26/32
31/32
AC!
克制住掀桌而起的疯狂心理,我摊在了地上。
由于当天晚上太累了,早早就睡了(颓废);所以并没有看F题,只是看了看E题的题面而已。
很遗憾,这场比赛没有发挥好,排名连前2000都没进。但是我感觉吸收到了太多东西,特别是Rating涨的37,是我前进的动力。
5.3还有一场比赛,加油吧!
直接暴力枚举即可。建议不要往数学的方面去想。
#include
#define int long long
using namespace std;
int a,l,r;
signed main()
{
cin>>a>>l>>r;
for (int i=l;i<=r;i++)
{
if (i%a==0) return cout<<"OK"<<endl,0;
}
cout<<"NG"<<endl;
return 0;
}
注意,若将一个整形量乘上一个float或double(1.01)量的值存到int里面去,那么它会自动保留整数部分。
由于答案最大为3760,所以直接模拟就可以了。
#include
#define int long long
using namespace std;
int n=100,x;
signed main()
{
cin>>x;
for (int i=1;i<=3760;i++)//while懒得写了
{
n=n*1.01;
if (n>=x) return cout<<i<<endl,0;
}
}
这一次的T3考验的是代码能力。
我们需要使用求组合的方式来得到数组 A A A的各个元素的值。如果您对组合计数不太熟悉,建议看下下面这部分。
①所有数都设为1(1 1 1 1);
②从右边往左边看,如果某个位置的数小于m,那么就把它加1并再从头往前看;
③如果第0个位置不再是0了,就1至 n n n的所有的位置都变成 m m m了;此时跳出循环。
for (int i=n;i>=0;i--)
{
if (now[i]<m)//now数组表示上面的A数组
{
now[i]++;
for (int j=i+1;j<=n;j++) now[j]=now[j-1];
break;
}
}
例如: n = 3 , m = 2 n=3,m=2 n=3,m=2。
1 1 1(第一步)
1 1 2(第三个位置不是m,加一)
1 2 2(第二个位置不是m,加一)
2 2 2(第一个位置不是m,加一)
然后 a 0 a_0 a0就变成1了,因此跳出循环。
#include
#define int long long
using namespace std;
int n,m,q,ans=-1e9-7;
int now[100005];
struct node
{
int a,b,c,d;
}que[100005];
signed main()
{
cin>>n>>m>>q;
for (int i=1;i<=q;i++) cin>>que[i].a>>que[i].b>>que[i].c>>que[i].d;
for (int i=1;i<=n;i++) now[i]=1;
while (now[0]==0)
{
int sumv=0;
for (int i=1;i<=q;i++)
{
if (now[que[i].b]-now[que[i].a]==que[i].c) sumv+=que[i].d;
}
ans=max(ans,sumv);
for (int i=n;i>=0;i--)
{
if (now[i]<m)
{
now[i]++;
for (int j=i+1;j<=n;j++) now[j]=now[j-1];
break;
}
}
}
cout<<ans<<endl;
return 0;
}
一道不错的数学贪心题。
首先,有一个很明显的东西,就是含有 x x x的分数的分母都是 b b b。最佳的 x x x可能由 n n n有关(不能超出上界),那是否与 b b b有关呢》
通过观察,发现当 x = b − 1 x=b-1 x=b−1的时候,原来的式子总是最大的。
但是有 n n n的限制,所以这里 x = m i n ( n , b − 1 ) x=min(n,b-1) x=min(n,b−1),才能让式子最大。
求出 x x x然后带进去就行啦。不要被 a ≤ 1 0 6 a≤10^6 a≤106给误导哦,这仅仅是为了防止下标溢出。
时间复杂度: O(1)
#include
#define int long long
using namespace std;
int a,b,n,N;
signed main()
{
cin>>a>>b>>N;
n=min(N,b-1);
cout<<((a*n)/b)-a*(n/b)<<endl;
return 0;
}
一道神仙 构造题,反正比赛的时候WA了无数次,就是没有想到正解。
即,分组,编号为 1 1 1到 m + 1 m+1 m+1算一组, m + 2 m+2 m+2到 n n n算另外一组。然后第一组中 1 1 1对 m + 1 m+1 m+1, 2 2 2对 m m m, 3 3 3对 m − 1 m-1 m−1……第二组同理,即 m + 2 m+2 m+2对 n n n, m + 3 m+3 m+3对 n − 1 n-1 n−1……
注意当已经凑足 m m m场比赛的时候立即停止,否则同时在第一组中和第二组中搞一场比赛( 1 1 1对 m + 1 m+1 m+1, m + 2 m+2 m+2对 n n n),这样的正确性是不言而喻 的。
时间复杂度: O ( m ) O(m) O(m)
我太难了……
#include
#define int long long
using namespace std;
int n,m,q,ans=-1e9-7;
int now[100005];
struct node
{
int a,b,c,d;
}que[100005];
signed main()
{
cin>>n>>m>>q;
for (int i=1;i<=q;i++) cin>>que[i].a>>que[i].b>>que[i].c>>que[i].d;
for (int i=1;i<=n;i++) now[i]=1;
while (now[0]==0)
{
int sumv=0;
for (int i=1;i<=q;i++)
{
if (now[que[i].b]-now[que[i].a]==que[i].c) sumv+=que[i].d;
}
ans=max(ans,sumv);
for (int i=n;i>=0;i--)
{
if (now[i]<m)
{
now[i]++;
for (int j=i+1;j<=n;j++) now[j]=now[j-1];
break;
}
}
}
cout<<ans<<endl;
return 0;
}
请教一下各位大佬,怎么在优先队列中删除一个元素?
如果我知道了,这篇题解就可以写了……