赛场或平时验证某一程序的正确性。
std.exe
程序(不要求时间)。dp
正确性。这个我不会教,也教不了、、
注意事项:
首先须知rand()
函数。
最重要的一点: r a n d ( ) ∈ [ 1 , 32767 ] rand()\in[1,32767] rand()∈[1,32767]。
因此,当我们想要造 1 0 9 10^9 109甚至 1 0 18 10^{18} 1018级别的随机数时,需手写 r a n d ( ) rand() rand()函数。
随机数范围 [ a , b ] [a,b] [a,b]
#define int long long
int rand9(int a, int b) {
int res = 0;
int t = rand();//最大只能至32767
for (int i = 1; i <= t; ++i)
res = (res + rand()) % (b - a + 1) + a;
return res;
}
各位可以在本地跑一下。
(是不是发现它只输出一个定值)
但是如果在主函数加一个srand(time(0))
呢?
#include
#define int long long
using namespace std;
int rand9(int a, int b) {
int res = 0;
int t = rand();//最大只能至32767
for (int i = 1; i <= t; ++i)
res = (res + rand()) % (b - a + 1) + a;
return res;
}
signed main() {
srand(time(0));
printf("%lld\n", rand9(1, 1000000000));
return 0;
}
再次尝试运行,发现趋于某个常数,但不稳定。
(不必要计算回归)
同理。
#include
#define int long long
using namespace std;
int rand9(int a, int b) {
int res = 0;
int t = rand();//最大只能至32767
for (int i = 1; i <= t; ++i)
res = (res + rand()) % (b - a + 1) + a;
return res;
}
int rand18(int a, int b) {
int res = 0;
int t = rand9(a, b);//最大只能至1073676289
for (int i = 1; i <= t; ++i)
res = (res + rand9(a, b)) % (b - a + 1) + a;
return res;
}
signed main() {
srand(time(0));
printf("%lld\n", rand18(1, 1000000000));
return 0;
}
从c++11开始c++多了一个新的STL
:mt19937
。
其中mt
指 m a x i n t maxint maxint;
19937
指其周期,为 2 19937 − 1 2^{19937}-1 219937−1。
当我看到这个东西的时候吓我一跳(确信)。
这个函数有一下几点好处:
有了这个函数,我们就可以快速完成 1 0 9 10^9 109数量级随机数的制造。
#include
#define int long long
using namespace std;
mt19937 rnd(time(0));
signed main() {
printf("%lld\n", rnd());
return 0;
}
1 0 18 10^{18} 1018同rand()
函数 1 0 9 10^9 109的造法。
这里直接贴代码。
#include
#define int long long
using namespace std;
mt19937 rnd(time(0));
signed main() {
printf("%lld\n", rnd() * rnd());
return 0;
}
注意观察特殊要求!!!
对于一个或多个无相关的读入直接输出随机数。
若有数据要求,需要排序。
以下对拍简称dp
(个人习惯)。
这个没什么好讲的。
可以了解一下windows.h
头文件与该头文件下system
函数。
#include
int main() {
while (1) {
system("sample.exe > 文件名.in");
system("文件名.exe < 文件名.in > 文件名.out");
system("std.exe < 文件名.in > 文件名.ans");
if (system("fc 文件名.out 文件名.ans"))
break;
}
return 0;
}
或者这样:
#include
#include
long long cnt;
int main() {
while (1) {
system("sample.exe > 文件名.in");
system("文件名.exe < 文件名.in > 文件名.out");
system("std.exe < 文件名.in > 文件名.ans");
if (system("fc 文件名.out 文件名.ans")) {
std::cerr << ++cnt << " WA\n";
break;
}
std::cerr << ++cnt << " AC\n";
}
return 0;
}
其中sample.exe
为造样例程序。
当考场不让使用cmd
的时候,略微修改也可以直接对拍已给出样例。
#include
int main() {
system("fc 文件名.out 文件名.ans");
return 0;
}
对于某一些特殊的题目,我们也可以有一些非常规对拍方法。
若某些题目背景为从答案出发的题目,我们能可以采用这种方法。
对于这种方法,我们需要改变 s t d std std的定义。
新定义:
这种方法难点仅此一点。
补充:对于绝大部分的 S P J SPJ SPJ,对拍程序大多采用该方法
本蒟蒻比较懒,但是同机房的大佬催着蒟蒻给一个示范,于是就有了这一栏。
本蒟蒻是真的蒟蒻,就写一个我最近打的氵题罢。
洛谷P7909分糖果
(话说这个是不是真的太水了)
先贴需拍代码。
#include
#define int long long
int n, l, r;
signed main() {
scanf("%lld%lld%lld", &n, &l, &r);
if (r > l + n) {
printf("%lld\n", n - 1);
return 0;
}
if (r / n == l / n) {
printf("%lld\n", r % n);
return 0;
}
printf("%lld\n", n - 1);
return 0;
}
显然这是一个AC
代码。
(趁Dev-C++不注意改一下。
#include
#define int long long
int n, l, r;
signed main() {
scanf("%lld%lld%lld", &n, &l, &r);
if (r > l + n) {
printf("%lld\n", n - 1);
return 0;
}
if (r / n == l / n + 1) {
printf("%lld\n", r % n);
return 0;
}
printf("%lld\n", n - 1);
return 0;
}
这样他就变成了一个 20 p t s 20pts 20pts的WA
代码。
接下来有一个很现实的问题。
暴力怎么写才能确保正确性。
对于这道题来说,只需 O ( r − l ) O(r-l) O(r−l)枚举所有可能性即可。
但是,对于其他算法题呢?
显然,搜索与枚举是一种很好的检测方式。
那么,