今天因为多校和 robocom 决赛冲突了,所以我们队大概只打了一个半小时(但是还是把三道签到题做完了),队友1一开始就发现 C 是签到题,简单交流了一下思路后就交给队友1写了,我和队友2一起看另外一道签到题 F ,队友2得出贪心的结论之后就由我开写,我们分别在45分钟过了 F ,52分钟过了 C,四点多打完 robocom 之后回来又看到 G 题过了一车人,我们将三种长度的 6 种情况讨论出来后一发过掉了 G,比赛结束。由于这把多校只打了一个多小时,所以剩下的题还是得找时间补一补的。
题意:给你一个数组 a a a ,让你构造一个从 1 − n 1-n 1−n 的排列 b b b ,数组 a [ i ] a[i] a[i] 的意思是在第 i i i 个位置中数组 b b b 的值不能为 a [ i ] a[i] a[i] ,即 b [ i ] ! = a [ i ] b[i]!=a[i] b[i]!=a[i] 如果能构造,则输出 Y E S YES YES 并将构造的数组 b b b 输出,不能则输出 N O NO NO
做法:
由观察我们容易得出,只要数组 a a a 不是只存在一种数字,则有解(全为一个数时无论如何 b 数组中也会有一个数使得 b [ i ] = a [ i ] b[i]=a[i] b[i]=a[i] ),我们可以考虑将数组 a a a 中出现的每种数及这种数的一个下标存起来,例如 1 1 2 3 4,我们则将(1,2)(2,3)(3,4)(4,5)存下,然后让数组 b b b 中 b [ 3 ] = 1 , b [ 4 ] = 2 , b [ 5 ] = 3 , b [ 2 ] = 4. b[3]=1,b[4]=2,b[5]=3,b[2]=4. b[3]=1,b[4]=2,b[5]=3,b[2]=4. 即将数字错位,然后再将剩余的数全部填到剩余的空位中(因为剩余的数没有出现在 a a a 中,因此我们可以以任意的方式填,也不会出现 a [ i ] = b [ i ] a[i]=b[i] a[i]=b[i] 的情况)
代码:
/*
author:wuzx
*/
#include
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n,m,k;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
map<int,int> mp;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>m;
mp[m]=i;//将每种数字的一个下标存进map里
}
if(mp.size()==1)//只有一种数时输出NO
cout<<"NO"<<endl;
else
{
cout<<"YES"<<endl;
vector<int> ans(n,0),vis(n+1,0);
vector<P> b;
for(auto [x,y]:mp)
b.emplace_back(x,y);
m=b.size();
for(int i=0;i<m;i++)//将第i种数的下表设为第i+1个数的下标,并记录这个数已经填了
{
auto [x,y]=b[(i+1)%m];
auto [x1,y1]=b[i];
ans[y]=x1;
vis[x1]=1;
}
int idx=1;
for(int i=0;i<n;i++)//将剩余的数填进空位里
{
if(!ans[i])
{
while(vis[idx])
idx++;
ans[i]=idx;
idx++;
}
}
for(auto x:ans)
cout<<x<<" ";
cout<<endl;
}
}
return 0;
}
题意:
给你一个环形数组,当数组中相邻两个元素满足 a [ i ] = a [ i + 1 ] a[i]=a[i+1] a[i]=a[i+1] 或 a [ i ] + a [ i + 1 ] = x a[i]+a[i+1]=x a[i]+a[i+1]=x ,可将这两个数从数组中消去,问最多能进行多少次消除操作。
做法:
这题队友2简单推了几种情况,觉得这是贪心,然后我就用并查集模拟循环链表,遇到能删除的直接删除即可。
代码:
/*
author:wuzx
*/
#include
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n,m,k;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>k;
vector<int> a(n),fa(n),pre(n);
for(int i=0;i<n;i++)
{
cin>>a[i];
fa[i]=i;
pre[i]=i;
}
function<int(int)> find = [&](int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
};
function<int(int)> find1 = [&](int x)
{
return pre[x]==x?x:pre[x]=find1(pre[x]);
};
int idx=0;
int ans=0;
int len=n;
int cnt=0;
while(1)
{
int nxt=find((idx+1)%n);
if(idx==nxt)
break;
// cout<
if(a[idx]+a[nxt]==k||a[idx]==a[nxt])
{
ans++;
len-=2;
int n1xt=find((nxt+1)%n);
fa[idx]=n1xt;
fa[nxt]=n1xt;
int pre1=find1((idx-1+n)%n);
pre[nxt]=pre1;
pre[idx]=pre1;
if(idx==pre1)
break;
idx=pre1;
cnt=0;
if(len<=1)
break;
}
else
{
idx=find((idx+1)%n);
cnt++;
}
if(cnt>len+10)
break;
}
cout<<ans<<endl;
return 0;
}
题意:
涉及正则表达式的知识,给你一个字符串问你用正则表达式最短能用几个字符表示出来,输出最短的正则表达式长度及个数。
做法:
考虑字符长度为 1 1 1 ,以 a a a 为例,此时只有两种情况 a a a 和 . .\space\space . 答案为 1 2
再考虑字符长度为 2 2 2 的情况,若两个字符相同,则有 a a a . . a a + . + . . . ∗ a ∗ aa\space a.\space .a\space a+\space .+\space ..\space .*\space a* aa a. .a a+ .+ .. .∗ a∗ 这长度为二的八种情况
若两个字符不相同,则有 a b a . . b . . . ∗ . + ab\space a.\space .b\space ..\space .*\space .+ ab a. .b .. .∗ .+ 这长度为二的六种情况
若字符长度大于2,若字符串中只有一种字符,则有 a + a ∗ . + . ∗ a+\space a* \space .+\space .* a+ a∗ .+ .∗ 这长度为二的四种情况
若字符串不止一种字符,则有 . ∗ . + .*\space .+ .∗ .+ 这长度为二的两种情况。
代码:
/*
author:wuzx
*/
#include
#define ll long long
#define int long long
#define endl "\n"
#define P pair<int,int>
#define f first
#define s second
using namespace std;
const int inf = 0x3f3f3f3f;
int t;
int n,m,k;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
{
string ss;
cin>>ss;
if(ss.size()==1)
cout<<1<<" "<<2<<endl;
else if(ss.size()==2)
{
if(ss[0]==ss[1])
cout<<2<<" "<<8<<endl;
else
cout<<2<<" "<<6<<endl;
}
else if(count(ss.begin(),ss.end(),ss[0])==ss.size())
cout<<2<<" "<<4<<endl;
else
cout<<2<<" "<<2<<endl;
}
return 0;
}