思路:贪心,我们尽可能让大的数和小的数进行匹配即可。
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;
void solve()
{
int n;
cin>>n;
vector<pll> a(n+5);
for(int i=1;i<=n;i++){
int x;
cin>>x;
a[i]={x,i};
}
vector<int> b(n+5);
sort(a.begin()+1,a.begin()+1+n);
for(int i=n;i>=1;i--){
int c=n-i+1;
b[a[c].second]=i;
}
for(int i=1;i<=n;i++) cout<<b[i]<<" ";
cout<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
system("pause");
return 0;
}
思路:我们发现回文字符串对应位置不匹配时的贡献为1,否则贡献为2,我们统计对应两种情况的贡献数目即可,然后根据字符串的长度进行分类讨论,因为当字符串长度为奇数时,中心字符也有1的贡献。
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;
void solve()
{
int n;
cin>>n;
string s;
cin>>s;
int cnt1=0;
int cnt2=0;
for(int i=0;i<(n+1)/2;i++){
if(s[i]==s[n-i-1]){
cnt1++;
}
else{
cnt2++;
}
}
vector<int> a(n+5);
if(n%2){//当为奇数时,中心字符串的贡献不计入为2的贡献中
for(int i=cnt2,j=0;j<cnt1;j++,i+=2){//只用对1进行修改
a[i]=1;
a[i+1]=1;
}
}
else{
for(int i=cnt2,j=0;j<=cnt1;j++,i+=2){
a[i]=1;
// a[i+1]=1;
}
}
for(int i=0;i<=n;i++) cout<<a[i];
cout<<endl;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
system("pause");
return 0;
}
思路:思维,我们操作Alice,除开第一次以外,我们可以贪心想到,bob拿走了什么数,我们就把他对应的数放进去即可,那么现在考虑第一次操作,因为我们想让结果最优,所以直接放入原序列的 m e x mex mex值即可。
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 998244353;
const int maxv = 4e6 + 5;
void solve()
{
int n;
cin>>n;
set<int> se;
for(int i=0;i<n;i++) {
int x;
cin>>x;
se.insert(x);
}
int res=0;
int c=0;
for(auto x: se){
if(x!=c) break;
c++;
}
cout<<c<<endl;
cout.flush();
while(1){
int x;
cin>>x;
if(x==-1) return;
cout<<x<<endl;
cout.flush();
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
int t = 1;
cin >> t;
while (t--)
{
solve();
}
system("pause");
return 0;
}
思路:我们构造b数组时,以a数组为 [ 2 , 3 , 4 , 2 ] [2,3,4,2] [2,3,4,2], k = 3 k=3 k=3,为例:
我们可以首先构造除 l = [ 1 , 2 , 3 ] l=[1,2,3] l=[1,2,3],那么此时的a数组为 [ 2 , 3 , 1 , 0 ] [2,3,1,0] [2,3,1,0],
我们可以接着构造 l = [ 2 , 3 , 4 ] l=[2,3,4] l=[2,3,4]那么此时的a数组为 [ 2 , 3 , 4 , 2 [2,3,4,2 [2,3,4,2。
我们根据上面的构造,我们会发现,若把下标和对应的点进行连边,我们会得到这样一个图,且对于每一个下标,我们需要在该位置放的值也刚好构成这样的关系。此时我们就考虑构造出来的图中,每个环上的节点是否为k即可。
因为如果环的节点个数不为k,那么我们无论如何也无法构造出合法的环。(因为根本不存在相应大小为k的环)。
具体考察的算法就是基环树,因为每个下标都跟值连单向边,所有只会有n条边存在。但整个不一定连同,所以其本质上是基环树森林。
#include
using namespace std;
const int N=4e7+5;
typedef long long ll;
typedef pair<ll,ll > pll;
typedef array<int,3> p3;
int mod=998244353;
const int maxv=4e6+5;
void solve()
{
int n,k;
cin>>n>>k;
vector<int >a(n+5);
for(int i=1;i<=n;i++) cin>>a[i];
if(k==1){//注意k等于1时要进行特判
for(int i=1;i<=n;i++){
if(a[i]!=i){
cout<<"NO"<<endl;
return ;
}
}
cout<<"YES"<<endl;
}
else{
vector<int> st(n+5,-1);
for(int i=1;i<=n;i++){
int j=i;
while(st[j]==-1){
st[j]=i;
j=a[j];
}
if(st[j]==i){
int cnt=0;
int x=j;
do{
cnt++;
x=a[x];
}while(x!=j);
if(cnt!=k){
cout<<"NO"<<endl;
return ;
}
}
}
cout<<"YES"<<endl;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}