A. Working Week
题意:有三个数,其中一个数在最后一个位置,另外两个数可以随意摆放,摆放后产生三个间隔l1,l2,l3
满足下列条件
- 两数之间互不相邻
- l1!=l2!=l3
最大化min(l1,l2,l3),若无任何位置满足上述条件输出0
//分奴分奴!!!!!!!!!!!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6+10;
const int mod = 998244353;
#define endl '\n'
int n,k,m;
ll a[maxn];
void solve(){
cin>>n;
if(n<=8){
cout<<0<<endl;
return;
}
int ans = (n-3)/3;
cout<<ans-1<<endl;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
B. Tea with Tangerines
题意:要求两两数之间满足条件 x<y∗2(x>=y)
贪心一下,因为两两之间都要满足,如果切割最小的数可能导致其他数要切割更多次,是不优的。那就是最小的数不动然后去切割其他数,每次都切割出最小的数 a1∗2−1 即可。
然后当某个数正好能整除 a1∗2−1 时,次数只需要 a[i]/(a1∗2−1)−1 即可,如果除不尽则需要a[i]/(a1*2-1)
赛后发现其实算次数是这么算,但是最后一次切割可能不会是 a1∗2−1 (当膜除不尽的时候),因为如果这样可能切个1出来不满足条件,最后一次切割应该是切出a1和a1+c的内容 (a1+c<a1∗2−1)
//分奴分奴!!!!!!!!!!!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6+10;
const int mod = 998244353;
#define endl '\n'
int n,k,m;
ll a[maxn];
void solve(){
cin>>n;
for(int i = 1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);
ll sum = 0;
for(int i = 2;i<=n;i++){
sum+=(a[i]/(2*a[1]-1));
if(a[i]%(2*a[1]-1)==0)
sum--;
}
cout<<sum<<endl;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
C. Phase Shift
题意:我们可以把每个字符进行一个映射,但是要求这个映射关系是可以组成一个26个字母成环,给你一个字符串f,问最后能得到的映射的最小字典序的字符串是什么
我们来看这个成环映射,其实可以看成一张图,每个点只有一个入度和出度
映射关系可以看成原字符串f[i] - > 新字符串s[i] ,那么最暴力的方式就是直接遍历整个原字符串, 对于每个原字符f[i]如果没有被映射过,那么遍历a-z,第一个没有被到达过的字符我们就建立一个映射关系。这样就能保证字典序最小
但是这样做是有矛盾的,比如ba这个,如果我们按上述思路暴力就会得到ab,是不满足我们26个字母的成环映射的。那么我们就一定要想办法避免这种提前成环。
那么我们使用并查集就好了,在建立映射关系的时候要保证f[i]和s[i]不属于同一个父类,这样就能保证不会成环。但是我们是要最后能够成环的,因此当我们的f[i]遍历了26个字母都不能建立映射的时候说明此时26个字母已经产生了完整的一条非环链,我们找到入度为0和出度仍然为0的点进行链接即可。
//分奴分奴!!!!!!!!!!!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6+10;
const int mod = 998244353;
#define endl '\n'
int n,k,m;
int a[maxn];
int f[100];
int vis[100];
int vis1[100];
int find(int x){
if(x==f[x])
return x;
return f[x] = find(f[x]);
}
void merge(int x,int y){
f[find(x)] = find(y);
}
void solve(){
map<char,char>z;
cin>>n;
string s;
cin>>s;
s = '?'+s;
for(int i = 1;i<=30;i++){
f[i] = i;
vis[i] = 0;
vis1[i] = 0;
}
for(int i = 1;i<=n;i++){
a[i] = int(s[i]-'a')+1;
}
for(int i = 1;i<=n;i++){
if(vis[a[i]])
continue;
int ok = 1;
for(int now = 1;now<=26;now++){
if(vis1[now])
continue;
if(now==a[i])
continue;
if(find(a[i])==find(now))
continue;
merge(a[i],now);
vis[a[i]] = 1;
vis1[now] = 1;
z[char(a[i]+'a'-1)] = char(now+'a'-1);
ok = 0;
break;
}
if(ok){
for(int j = 1;j<=26;j++){
if(!vis1[j]){
vis[a[i]] = 1;
vis1[j] = 1;
z[char(a[i]+'a'-1)] = char(j+'a'-1);
}
}
break;
}
}
for(int i = 1;i<=n;i++)
cout<<z[s[i]];
cout<<endl;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
cin>>t;
while(t--){
solve();
}
}
D. Meta-set
题意:每张卡片都有k个元素,每个元素的赋值只可能是0,1,2,三张卡如果每个元素要么相同要么都不同的时候,我们就说这三张卡是一组good,我们说五张卡中如果能选出至少两组good,那么这五张卡被称为一队,问有几队。
我们先考虑队,对于每个队中的三张卡而言,每个元素实际上是两个状态,要么相同,要么完全不同,换而言之,如果我们枚举两张卡,能和这两张卡组成一队的卡是固定的。由于k只有20,我们可以通过状态压缩把每张卡给压缩成一个long long(实际int就够了),然后我们把所有卡存进map中表示此卡是否出现过。我们 O(n2) 枚举两张卡,然后确定出第三张卡 O(logn) 查找一下是否存在这张卡,就可以确定出所有的组。确定出总复杂度 ()O(n2logn) 。
查找出所有组后我们考虑组和队之间的关系,很明显,组和组之间是只能共用一张卡的,如果共用三个卡就是相同组,共用两张卡但是两张卡能确定唯一的第三张卡,所以不可能共用两张卡。只有当共用一张卡时才满足5张卡至少两组,换而言之实际上五张卡最多也就两组。
由于一队的两组共用同一张卡,设每一张卡所在的组为n,其对于队数的贡献是 Cn2 (选取任意两组即可),那么我们存下每张卡的所在组数最后统计即可。
//分奴分奴!!!!!!!!!!!!
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 1e6+10;
const int mod = 998244353;
#define endl '\n'
int n,k,m;
int a[maxn][21];
ll b[maxn];
int ji[100];
map<ll,int>mm,zu;
void solve(){
cin>>n>>k;
ji[1] = 1;
for(int i = 2;i<=k;i++){
ji[i] = ji[i-1]*3;
}
for(int i = 1;i<=n;i++){
ll sum = 0;
for(int j = 1;j<=k;j++){
cin>>a[i][j];
sum+=ji[j]*a[i][j];
}
mm[sum] = 1;
b[i] = sum;
}
for(int i = 1;i<=n;i++){
for(int j = i+1;j<=n;j++){
ll sum = 0;
for(int w = 1;w<=k;w++){
if(a[i][w]==a[j][w]){
sum+=a[i][w]*ji[w];
}
else{
if(a[i][w]+a[j][w]==1)
sum+=2*ji[w];
else if(a[i][w]+a[j][w]==2)
sum+=1*ji[w];
}
}
if(mm.find(sum)!=mm.end()){//存在这样的组
zu[b[i]]++;
zu[b[j]]++;
zu[sum]++;
}
}
}
ll ans = 0;
for(auto i : zu){
int num = i.second/3;
//cout<<i.first<<" "<<num<<endl;
ll cnt = 1ll*num*(num-1)/2;
ans+=cnt;
}
cout<<ans<<endl;
}
int main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int t = 1;
//cin>>t;
while(t--){
solve();
}
}