第四题,题是看懂了,但是真不会写。想不出来,对图都不是太熟练,加上概率就更不太行了。
A题 A - Pretty Permutations
就是一个求交换位置的最小步数。
想着就是如果n是偶数,第一第二交换位置,第三第四交换位置,这样交换n次就可以构成解。
如果n是奇数,也很简单呀,我们在偶数处理的基础上,单独对a[n]跟a[n-1]交换一下位置就可以了。
// god with me
//#pragma GCC optimize(1)
//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#include <cmath>
#include <math.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define inf 0x7fffffff
#define ll long long
//#define int long long
//#define double long double
//#define double long long
#define re int
//#define i int i
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
// typedef long long s64;
using namespace std;
const int mod=1e6+7;
const int N=2e2+5;//?????????? 4e8
const int M=1e5+10;
const int maxn=32005;
int n;
int a[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)a[i]=i;
if(n%2==0)
{
for(int i=1;i<=n;i++)
{
if(i%2==1)swap(a[i],a[i+1]);
}
for(int i=1;i<=n;i++)cout<<a[i]<<" ";
cout<<endl;
}
else
{
for(int i=1;i<n;i++)
{
if(i%2==1)swap(a[i],a[i+1]);
}
swap(a[n-1],a[n]);
for(int i=1;i<=n;i++)cout<<a[i]<<" ";
cout<<endl;
}
}
signed main()
{
// ios::sync_with_stdio(false);
int T=1;
cin>>T;
for(int index=1;index<=T;index++)
{
solve();
}
return 0;
}
B题 B - Pleasant Pairs
题目的意思就是有一个数组,现在让你求数组中i<j and a[i]*a[j]==i+j的满足这种的二元组的数量呗。
看时间复杂度是要小于n2的。可以nlogn
首先想着暴力肯定不行,那肯定要优化。如果要优化的话,首先是
想法一: I+j是a[i]的倍数,如果我每次枚举i和a[i]我可以j向后每次跳a[i],后来想了一下n/a[i] * n 那不还是很大么。
想法二:a[i]*a[j]-i==j 那么我枚举a[i]和i然后我用j = t * a[i]+i 每次跳a[i] ,这不还是一样的操作么。
这里忽然想到题目说a[i]的值不同,那n/a[i]那不就是相当于log级的么 第一个第二个想法都可以跑了。
// god with me
//#pragma GCC optimize(1)
//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#include <cmath>
#include <math.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
//#define double long long
#define re int
//#define i int i
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
// typedef long long s64;
using namespace std;
const int mod=1e6+7;
const int N=2e5+5;//?????????? 4e8
const int M=1e5+10;
const int maxn=32005;
int n;
int a[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
int cnt=0;
for(int i=1;i<=n;i++)
for(int j=a[i]-i;j<=n;j+=a[i])
{
if(j<=i) continue;
if(a[i]*a[j]==i+j) cnt++;
}
cout<<cnt<<endl;
}
signed main()
{
// ios::sync_with_stdio(false);
int T=1;
cin>>T;
for(int index=1;index<=T;index++)
{
solve();
}
return 0;
}
C题 C. Great Graphs
大概的意思就是给了你一个数组,d[i]的意思就是从1 到 i 的距离。 要求把他们连起来并且求和最小。注意如果a->b的代价为x 那么b->a的代价就是-x
这里对数组进行一个距离的排序。因为比如我们到2的距离为4,到3的距离为5。不是就可以只建立从1到2的和从2到3的 这样一共花费的代价不就是5了么。
这样就很明显了。如果我从1到一个位置的值为负数。我直接连接就好了呀。
当然,如果是正数的情况下。我们就基于上一次的位置来继续连。
这里我们就要来考虑一下如果是正数的情况下我们向回连接的话就一定是负数。假设全部是正节点,在第i个正节点向前面一个链接。i-1的路径走了一次,向前面两个链接,i-1走一次,i-2走一次等等等。
最后我们发现每添加一个节点,前面那个路走的次数可易发生变化
比如
0 1 2 3
回填:
-1
-1 -2
-1 -2 -3
我第一次没有考虑多0也可以增加回填的情况就WA了一发。cnt要加的。交快了
// god with me
//#pragma GCC optimize(1)
//#pragma GCC optimize(2)
//#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#include <cmath>
#include <math.h>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
//#define double long long
#define re int
//#define i int i
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
// typedef long long s64;
using namespace std;
const int mod=1e6+7;
const int N=1e5+5;//?????????? 4e8
const int M=1e5+10;
const int maxn=32005;
int n;
int a[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
int ans=0;
int sum=0,now=0;
int cnt=0;
int distance=0;
for(int i=1;i<=n;i++)
{
if(a[i]<0)ans+=a[i];
else
{
distance=a[i]-now;
ans+=distance;
sum+=cnt*distance;
cnt++;
ans-=sum;
now=a[i];
}
// cout<<ans<<endl;
}
cout<<ans<<endl;
}
signed main()
{
// ios::sync_with_stdio(false);
int T=1;
cin>>T;
for(int index=1;index<=T;index++)
{
solve();
}
return 0;
}
D题 D. Tree Array
大概的意思就是给了你一个树。然后说我们要在树上选节点放到数组里面。最初选的时候就是每个节点都有等概率的机会,在此之后我们只能选择,已经被选择过的节点的相连的节点。 概率都是相等的。
我们求出来所有的数组情况下根据概率乘以一个系数。这个系数就是我们所选出来的数组里面存在的逆序列。
这里的逆序列指的是i<j but a[i]>a[j] 这样的概率 最后说如果是一个分数的情况下,做一个取模求余的操作。
emmmmmm
没有思路,找规律肯定不行,是没有规律的。那么只能搜,搜索的话想想每个节点的概率问题再向后延伸。麻了 想不出来
看了题解好像是 概率+DP+LCA