2022.08.27 模拟赛小结
2022.08.27 模拟赛小结
题面
(这个链接只是为了自己方便找,页面设置权限了,不要尝试访问)
更好的阅读体验戳此进入
(建议您从上方链接进入我的个人网站查看此 Blog,在 Luogu 中图片会被墙掉,部分 Markdown 也会失效)
赛时思路
T1
原题是 LOJ-535 「LibreOJ Round #6」花火 ,题意大概是一个序列,然后可以将其中任意两个值调换位置一次,然后再求逆序对个数。
只是求逆序对的话显然 $ O(n log n) $ 随便过,但是加上这个调换位置确实是直接不会了,想了半天也没什么好的思路,最后只能想到枚举+树状数组 $ O(n^3logn) $ 但是显然只能过 $ 30% $,然后写了两行之后就决定干脆 $ O(n^4) $ 做得了,反正得分应该没区别,就没必要多浪费时间了。
然后呢和我预料的差不多,25pts,小点里有一个 WA 了,不知道是哪里寄掉了。
Code:
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long unll;
typedef long double ld;
typedef unsigned int uint;
#define npt nullptr
#define PI M_PI
#define E M_E
template < typename T = int >
inline T read(void);
// struct Tree{
// int arr[61000];
// int lim;
// int lowbit(int x){return x & (-x);}
// void push(int v){while(x <= lim){arr[x] += x}}
// }
int N;
int a[610000];
int main(){
freopen("swaq.in", "r", stdin);
freopen("swaq.out", "w", stdout);
N = read();
for(int i = 1; i <= N; ++i)a[i] = read();
if(N <= 500){
// int times(0);
// for(int i = 1; i <= N; ++i){
// for(int j = i + 1; j <= N; ++j){
// if(i > j)++times;
// }
// }
// int maxx(0);
// for(int i = 1; i <= N; ++i){
// for(int j = 1; j <= N; ++j){
// }
// }
int minn = INT_MAX;
for(int i = 1; i <= N; ++i){
for(int j = i + 1; j <= N; ++j){
swap(a[i], a[j]);
int sum(0);
for(int k = 1; k <= N; ++k){
for(int l = k + 1; l <= N; ++l){
if(a[l] < a[k])++sum;
}
}
// for(int i_ = 1; i_ <= N; ++i_)printf("%d ", a[i_]);
// printf(" ans is %d\n", sum);
swap(a[i], a[j]);
minn = min(minn, sum);
}
}
printf("%d\n", minn + 1);
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
T flag(1);
char c = getchar();
while(!isdigit(c) && c != '-')c = getchar();
if(c == '-'){flag = -1; c = getchar();}
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
T2
原题是 HDU-7262 三角函数(为了方便就给个 vjudge 的链接吧),是一个欧几里得的题,或者说的更准确应该是个更相减损的题,有很多性质然后最后可以转化为更相减损,很考验思维。不过赛时雀食没推出来,用了一些乱搞的做法最终拿到了 10pts,(如果是 NOILinux 评测环境的话有可能会高一点,用到的 __float128 在 MinGW 里会失效)。
然后还有一个特别 sb 的错误,我用 __float128 来让精度极高,然后判等的时候 eps 我直接设置的 $ 1 \times 10^{-5} $,直接导致精度太低然后让某些数经过很多次 $ arctan $ 计算后近似相等,我感觉甚至改成 $ 1 \times 10^{-20} $ 应该都行。
回到我的乱搞做法,观察发现输入数据只有两个数,而且部分分范围很低,所以考虑数据库思想自动生成一个大表,用一些奇怪的 BFS,(这题的状态用宽搜确实难搜,我最后用队列里套 pair 套 __float128 和 枚举类型的 vector ),或者迭代加深 DFS 似乎也行???
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long unll;
typedef long double ld;
typedef unsigned int uint;
typedef __float128 f128;
#define npt nullptr
#define PI M_PI
#define E M_E
template < typename T = int >
inline T read(void);
#define eps (f128)(1e-5)
bool cmp(f128 a, f128 b){return fabs((double)a - (double)b) <= eps;}
f128 x;
f128 ans;
#define vf vector < func >
enum func{sinn = 1, coss, atann, out_of_range__};
vf oper;
/*void bfs(int q__){
double begT = (double)clock() / CLOCKS_PER_SEC;
queue < pair < f128, vf > > q;
vf empt;
q.push(make_pair((f128)0.0, empt));
while(!q.empty()){
auto head = q.front(); q.pop();
// if(cmp(head.first, ans)){
// oper = head.second;
// return;
// }
// if((double)clock() / CLOCKS_PER_SEC >= 0.90)return;
for(func f = sinn; f <= atann; f = func(f + 1)){
head.second.push_back(f);
// printf("current: %.5lf\n", (double)head.first);
f128 tmp(0.0);
switch(f){
case sinn:{
tmp = sinf128(head.first);
break;
}
case coss:{
tmp = cosf128(head.first);
break;
}
case atann:{
tmp = atanf128(head.first);
break;
}
default:{
printf("error\n");
break;
}
}
if(cmp(tmp, ans)){
oper = head.second;
return;
}
if((int)head.second.size() > q__ * 2 + 1 || (double)clock() / CLOCKS_PER_SEC >= 0.80){
printf("None");
oper.clear();
return;
}
// head.first = tmp;
q.push(make_pair(tmp, head.second));
head.second.pop_back();
}
}
}
void CAL(int p, int q){
// fprintf(stderr, "caling p=%d, q=%d\n", p, q);
oper.clear();
ans = sqrtf128((f128)p / (f128)q);
// printf("%.7lf\n%.7lf\n", (double)ans, (double)(sin(atan(cos(0.0)))));
// printf("else if(p==%d&&q==%d)printf(\"", p, q);
bfs(q);
// reverse(oper.begin(), oper.end());
for(auto i : oper){
switch(i){
case sinn:{
printf("s");
break;
}
case coss:{
printf("c");
break;
}
case atann:{
printf("t");
break;
}
default:{
printf("error\n");
break;
}
}
}
// printf("\\n\");\n");
printf("\n");
// if(p % 5 == 0 || q % 5 == 0){
// printf("\n");
// // fprintf(stderr, "Complete p=%d, q=%d\n", p, q);
// // fflush(stderr);
// }
// fflush(stdout);
}
*/
//这里因为测评用的MinGW,所以我用的__float128会CE,所以只能注释掉了
int main(){
freopen("luckysct.in", "r", stdin);
freopen("luckysct.out", "w", stdout);
int p = read(), q = read();
if(p==1&&q==1)printf("c\n");
else if(p==1&&q==2)printf("cts\n");
else if(p==2&&q==2)printf("c\n");
else if(p==1&&q==3)printf("ctsts\n");
else if(p==2&&q==3)printf("ctstc\n");
else if(p==3&&q==3)printf("c\n");
else if(p==1&&q==4)printf("ctststs\n");
else if(p==2&&q==4)printf("cts\n");
//......
//剩下的就先删掉了,一大片表
else ;//CAL(p, q);
// fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
T flag(1);
char c = getchar();
while(!isdigit(c) && c != '-')c = getchar();
if(c == '-'){flag = -1; c = getchar();}
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
Build Code: (生成表用的程序)
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long unll;
typedef long double ld;
typedef unsigned int uint;
typedef __float128 f128;
#define npt nullptr
#define PI M_PI
#define E M_E
#define eps (f128)(1e-5)
template < typename T = int >
inline T read(void);
bool cmp(f128 a, f128 b){return fabsf128(a - b) <= eps;}
f128 x;
f128 ans;
#define vf vector < func >
enum func{sinn = 1, coss, atann, out_of_range__};
vf oper;
void bfs(int q__){
double begT = (double)clock() / CLOCKS_PER_SEC;
queue < pair < f128, vf > > q;
vf empt;
q.push(make_pair((f128)0.0, empt));
while(!q.empty()){
auto head = q.front(); q.pop();
// if(cmp(head.first, ans)){
// oper = head.second;
// return;
// }
// if((double)clock() / CLOCKS_PER_SEC >= 0.90)return;
for(func f = sinn; f <= atann; f = func(f + 1)){
head.second.push_back(f);
// printf("current: %.5lf\n", (double)head.first);
f128 tmp(0.0);
switch(f){
case sinn:{
tmp = sinf128(head.first);
break;
}
case coss:{
tmp = cosf128(head.first);
break;
}
case atann:{
tmp = atanf128(head.first);
break;
}
default:{
printf("error\n");
break;
}
}
if(cmp(tmp, ans)){
oper = head.second;
return;
}
if((int)head.second.size() > q__ * 2 + 1 || (double)clock() / CLOCKS_PER_SEC - begT >= 5.00){
printf("None");
oper.clear();
return;
}
// head.first = tmp;
q.push(make_pair(tmp, head.second));
head.second.pop_back();
}
}
}
void CAL(int p, int q){
fprintf(stderr, "caling p=%d, q=%d\n", p, q);
oper.clear();
ans = sqrtf128((f128)p / (f128)q);
// printf("%.7lf\n%.7lf\n", (double)ans, (double)(sin(atan(cos(0.0)))));
printf("else if(p==%d&&q==%d)printf(\"", p, q);
bfs(q);
// reverse(oper.begin(), oper.end());
for(auto i : oper){
switch(i){
case sinn:{
printf("s");
break;
}
case coss:{
printf("c");
break;
}
case atann:{
printf("t");
break;
}
default:{
printf("error\n");
break;
}
}
}
printf("\\n\");\n");
// if(p % 5 == 0 || q % 5 == 0){
// printf("\n");
// // fprintf(stderr, "Complete p=%d, q=%d\n", p, q);
// // fflush(stderr);
// }
fflush(stdout);
}
bool check(int p, int q){
for(int i = 2; i * i <= min(p, q); ++i){
if(p % i == 0 && q % i == 0)return false;
}
return true;
}
int main(){
// int p = read(), q = read();
// printf("\n");
// fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
freopen("/home/jdoi/cpp/OI/Exams/Monkey/luckysct/build.txt", "w", stdout);
for(int q = 10; q <= 1000; ++q){
for(int p = 1; p <= q; ++p){
if(check(p, q))CAL(p, q);
}
}
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
T flag(1);
char c = getchar();
while(!isdigit(c) && c != '-')c = getchar();
if(c == '-'){flag = -1; c = getchar();}
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
T3
一个我感觉挺离谱的整体二分+树形 DP,思路奇奇怪怪,赛时我是没想出来,不过给的几个特殊性质点还是非常容易就能想到的。
然后考虑暴力我不会写不好写,所以想到了个很奇怪的贪心,大概就是考虑只删 dist 相同的一层,然后显然能删的数量和 dist 相同,排序之后找对应的第 dist 大的数,简而言之就是个很奇怪的乱搞(我都不知道怎么想到的),不过最后居然对了好几个点,直接 35pts。
Code:
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long unll;
typedef long double ld;
typedef unsigned int uint;
#define npt nullptr
#define PI M_PI
#define E M_E
#define int ll
template < typename T = int >
inline T read(void);
int N;
struct Edge{
Edge* nxt;
// int val;
int to;
void* operator new(size_t);
Edge(Edge* nxt, int to):nxt(nxt), to(to){;}
Edge(void) = default;
}eData[210000];
void* Edge::operator new(size_t){static Edge* P = eData; return ++P;}
Edge* head[210000];
int deg[210000], val[210000];
int maxdeg(0);
const int root(1);
int dist[210000];
vector < int > nums[210000];
int maxdist(0);
void dfs_dist(int p){
for(auto i = head[p]; i; i = i->nxt){
dist[i->to] = dist[p] + 1;
dfs_dist(i->to);
nums[dist[i->to]].push_back(val[i->to]);
maxdist = max(maxdist, dist[i->to]);
}
}
signed main(){
freopen("ssq.in", "r", stdin);
freopen("ssq.out", "w", stdout);
N = read();
for(int i = 2; i <= N; ++i)val[i] = read();
for(int i = 1; i <= N - 1; ++i){
int f = read(), t = read();
head[f] = new Edge(head[f], t);
deg[f]++, deg[t]++;
maxdeg = max(maxdeg, max(deg[f], deg[t]));
}
if(deg[1] == 1 && maxdeg <= 2){
printf("0\n");
return 0;
}
if(deg[1] <= 2 && maxdeg <= 2){
int ans(0);
for(auto i = head[1]; i; i = i->nxt){
ans = max(ans, val[i->to]);
}
printf("%lld\n", ans);
return 0;
}
int ans(0);
dfs_dist(1);
for(int i = 1; i <= maxdist; ++i){
if(nums[i].size() <= i)continue;
sort(nums[i].begin(), nums[i].end(), greater<int>());
ans = max(ans, nums[i].at(i));
}
printf("%lld\n", ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
T flag(1);
char c = getchar();
while(!isdigit(c) && c != '-')c = getchar();
if(c == '-'){flag = -1; c = getchar();}
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
T4
大概是做的最崩的一道题,首先写这题的时候人已经困傻了,大概梦游了 0.5~1.0h 然后开始写,最后开始写暴力,然后就是没写出来,感觉题意都没完全理解,所以最后无奈直接写了个输出 rand(),然后不出所料 0pts。
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long unll;
typedef long double ld;
typedef unsigned int uint;
#define npt nullptr
#define PI M_PI
#define E M_E
#define MOD 998244353
template < typename T = int >
inline T read(void);
mt19937 _rnd(random_device{}());
int rnd(void){return _rnd() % INT_MAX;}
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
int N, M;
int atk[11000], def[11000];
int pos[11000], l[11000], r[11000];
int cnt(0);
vector < int > opt;
bool vis[110000];
bool used[110000];
void explode(int x, int w){
if(!used[x] && w > def[x]){
if(x != 1 && !used[x - 1]){
used[x - 1] = true;
vis[x - 1] = true;
explode(x - 1, atk[x] - l[x]);
}
if(x != N && !used[x + 1]){
used[x + 1] = true;
vis[x + 1] = true;
explode(x + 1, atk[x] - r[x]);
}
}
}
bool check(){
memset(vis, false, sizeof(vis));
for(auto i : opt){
memset(used, false, sizeof(used));
explode(pos[i], INT_MAX);
}
for(int i = 1; i <= N; ++i){
if(!vis[i])return false;
}
return true;
}
void dfs(int dep){
if(dep > M){
if(check())++cnt;
return;
}
dfs(dep + 1);
opt.push_back(dep);
dfs(dep + 1);
opt.pop_back();
}
int main(){
freopen("dota.in", "r", stdin);
freopen("dota.out", "w", stdout);
int T = read();
while(T--){
cnt = 0;
N = read(), M = read();
for(int i = 1; i <= N; ++i)atk[i] = read(), def[i] = read();
for(int i = 1; i <= M; ++i)pos[i] = read(), l[i] = read(), r[i] = read();
// dfs(1);
// printf("%d\n", cnt);
printf("%d\n", rndd(1, 315));
}
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
T flag(1);
char c = getchar();
while(!isdigit(c) && c != '-')c = getchar();
if(c == '-'){flag = -1; c = getchar();}
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
正解
T2
这题我挺喜欢,单独写一个 Blog 吧,戳此进入。
T1
咕咕咕
T3
咕咕咕
T4
咕咕咕
UPD
update-2022_8_27 初稿