这次cf打的额,是菜中菜
文章目录
A - Traveling Salesman Problem
- 思路:
最短路径在y轴上面走的步数是 (ymax - ymin ) * 2 (ymax是y >= 0的最大值,ymin是y <= 0的最小值,来回乘2,)同理在x轴上面走的步数是(xmax - xmin ) * 2 ,所以一共走 (ymax - ymin ) * 2 + (xmax - xmin ) * 2 - 代码:
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int>
using namespace std;
const int N = 2e5 + 100,M = N * 2,INF = 0x3f3f3f3f;
void solve()
{
int n; cin >> n;
int xmin = 0,xmax = 0,ymin = 0,ymax = 0;
for(int i = 1;i <= n;i ++ )
{
int x,y; cin >> x >> y;
if(x == 0)
{
if(y >= 0)
ymax = max(ymax,y);
else
ymin = min(ymin,y);
}
else if(y == 0)
{
if(x > 0)
xmax = max(xmax,x);
else
xmin = min(xmin,x);
}
}
int u = (ymax - ymin) * 2 + (xmax - xmin) * 2;
cout << u << endl;
}
signed main()
{
ios;int T; cin >> T; while(T -- ) solve();
return 0;
}
B - Optimal Reduction
- 思路:
你最终发现,最优先的路径一定是先递增后递减的,直接模拟
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int>
using namespace std;
const int N = 2e5 + 100,M = N * 2,INF = 0x3f3f3f3f;
int a[N],b[N];
void solve()
{
int n; cin >> n;
for(int i = 1;i <= n;i ++ ) cin >> a[i];
int id = 0;
for(int i = 1;i <= n - 1;i ++ )
{
if(a[i] <= a[i + 1]) continue;
else
{
id = i;
break;
}
}
if(id == 0) cout << "YES" << endl;
else
{
for(int i = id;i <= n - 1;i ++ )
{
if(a[i] < a[i + 1])
{
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
}
}
signed main()
{
ios;int T; cin >> T; while(T -- ) solve();
return 0;
}
C - Build Permutation
- 思路:
因为n的范围在1e5之内,所以x最多取 s q r t ( 1 e 5 ) sqrt(1e5) sqrt(1e5),不超过400,所以直接硬暴力就行,因为 i + a[i] = x * x,下标为(x * x - i)的也就找到了,那当下标为 i 的也就找到了,比如 3 + 6 = 9,a[6] = 3,那a[3] = 6,从后往前就行
- 代码:
#include <bits/stdc++.h>
#define int long long
#define ios ios::sync_with_stdio(0),cin.tie(0)
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int>
using namespace std;
const int N = 2e5 + 100,M = N * 2,INF = 0x3f3f3f3f;
int a[N],b[N];
int ans[N];
bool st[N];
void solve()
{
int n; cin >> n;
memset(st,false,sizeof st);
for(int i = n - 1;i >= 0;i -- )
{
int f = 0;
if(st[i])continue;
if(!st[i])
{
for(int j = 400;j >= 0;j -- )
{
if(j * j - i >= 0 && j *j - i <= n - 1)
{
if(!st[j * j - i] && !st[i])
{
st[j * j - i] = true;
st[i] = true;
ans[j * j - i] = i;
ans[i] = j * j - i;
f = 1;
break;
}
}
}
}
if(f == 0)
{
cout << "-1" << endl;
return;
}
}
for(int i = 0;i <= n - 1;i ++ ) cout << ans[i] << ' ';
cout << endl;
}
signed main()
{
ios;int T; cin >> T; while(T -- ) solve();
return 0;
}
D - Tournament Countdown
- 思路:
限定了询问次数,比如n = 2,那就最多两次询问,那看如何在两次询问中找到冠军,我们首先可以知道,n = 2,只有三场比赛,那4个数字里面,一定有两个人的胜场是0,且一个分布在[1,2]一个分部在[2,4],一定有一个人的胜场是2,另一个人的胜场是1,那我们首先比较1 和 3,如果1 == 3,代表胜者肯定是在2和4里面产生的,如果1 > 3 那2,3一定不是冠军,那冠军一定在1 和 3产生,同理如果1 < 3 ,那1,4一定不是冠军,那冠军一定在2 和 3产生,这样只需要两次,同理从5 到 8 也是一样… 等等都是这样,模拟即可 - 代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 150000,M = N * 2,INF = 0x3f3f3f3f;
int a[N];
int ask(int c,int b)
{
cout << "? " << c << " " << b << endl;
int k;
cin >> k;
return k;
}
void query(int n)
{
int s = 1;
int qq = 1;
int u = pow(2,n);
while(s < u)
{
int k = ask(a[s],a[s + 2]);
if(k == 0)
{
int k1 = ask(a[s + 1],a[s + 3]);
if(k1 == 1)
a[qq] = a[s + 1];
else
a[qq] = a[s + 3];
}
else if(k == 1)
{
int k1 = ask(a[s],a[s + 3]);
if(k1 == 1)
a[qq] = a[s];
else
a[qq] = a[s + 3];
}
else
{
int k1 = ask(a[s + 2],a[s + 1]);
if(k1 == 1)
a[qq] = a[s + 2];
else
a[qq] = a[s + 1];
}
s += 4;
qq ++;
}
}
void solve()
{
int n;
cin >> n; // 先两次确定一个胜者,两次确定一个胜者
int u = pow(2,n);
for(int i = 1;i <= u;i ++ ) a[i] = i;
while(n > 0)
{
if(n == 1)
{
int k = ask(a[1],a[2]);
if(k == 1) cout << "! " << a[1] << endl;
else cout << "! " << a[2] << endl;
return;
}
query(n);
n -= 2;
if(n == 0)
{
cout << "! " << a[1] << endl;
}
}
}
int main()
{
int T; cin >> T; while(T -- ) solve();
return 0;
}