用map计数,如果某字符串出现的次数刚好等于n,那么就需要输出,map会自动按字符串字典序升序,所以最后遍历map输出即可
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<map>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
map<string,int>mp;
int n;
void solve() {
cin>>n;
int m=n;
while(m--){
int c;
cin>>c;
for(int i=0;i<c;i++){
string s;
cin>>s;
mp[s]++;
}
}
int cnt=0;
for(auto v:mp){
if(v.second==n) cnt++;
}
cout<<cnt<<endl;
for(auto v:mp){
if(v.second==n) cout<<v.first<<endl;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--)
solve();
return 0;
}
H.Insert 1,Insert 2,Insert 3,...
参考2023牛客多校第八场题解 - 知乎 (zhihu.com)
我们从链的角度考虑,比如1,2,3,4是完整的一条链,1,2,3是完整的一条链
但是我们在找链的时候,为了方便,我们从右往左找,因为所有链的最左端都是固定不变的,均为1,但是链的最右端我们并不知道能延伸到哪里
对于一个合法的区间,可以拆分成若干条完整的链,比如说(1,2)是一条完整的链,那么该区间对答案的贡献度即为其长度2,more specifically,1算一个,1 2算一个
又比如说,(1,1,2,2,1,1,3,4,2,3)是一条完整的链,可以拆分成(1,2,3,4)+(1,2,3)+(1,2)+(1),那么该区间对答案的贡献度即为其长度10,more specifically,1算一个,1 1算一个, 1 1 2算一个,1 1 2 2算一个, 1 1 2 2 1算一个,1 1 2 2 1 1算一个, 1 1 2 2 1 1 3算一个,1 1 2 2 1 1 3 4算一个,1 1 2 2 1 1 3 4 2算一个,1 1 2 2 1 1 3 4 2 3算一个
首先,我们将下标n+1放入set中(注意,set自动升序,又由于下标从大到小遍历,所以相当于每次把下标插在左边)
从右往左扫,对于下标i,当a[i]+1在后面出现过时,我们就把值为a[i]+1的下标idx从set中删去(先删去下标小的那个,因为我们需要连续的区间),然后我们就知道从下标i到*s.begin()-1这个区间是若干条完整的链的尾部(头部还不完整,但是尾部已经完整了),当下标i所对应的值为1的时候,那么不仅链的尾部完整了,头部也完整了,也就说明从下标i到*s.begin()-1这个区间是若干条完整的链,所以该区间的贡献度即为该区间的长度,即*s.begin()-i(当枚举到值为1的下标时才统计答案)
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<vector>
#include<cstdio>
#include<map>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
void solve()
{
int n; cin >> n;
vector<int> a(n + 1);
for(int i = 1; i <= n; i++) cin >> a[i];
vector< vector<int> > pos(n + 2);
set<int> s{n + 1};//set中的唯一元素为n+1
ll ans = 0;
for(int i = n; i >= 1; i--)
{
if( pos[a[i] + 1].size() )
{
int p = pos[a[i] + 1].back();
pos[a[i] + 1].pop_back();
s.erase(p);
}
if(a[i] != 1)
{
s.insert(i);
pos[a[i]].push_back(i);
}
if(a[i]==1) ans += *s.begin() - i;
// printf("diff=%d-%d=%d\n",*s.begin(),i,*s.begin()-i);
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
// cin>>t;
while(t--)
solve();
return 0;
}
原本是想打表的,用dfs枚举所有情况,但实际并不可行,因为情况太多了,枚举出了也找不出规律
该题是构造题,正解应该是找到构造的一般规律,使得用一种规律可以构造出一个满足条件的序列
注意,质数除了2,其它全部都是奇数
打表代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
const int N=110;
int n;
int cnt;
int prime[N];
int path[N];
bool ok[N];
bool st[N];
set<int>s;
//质数筛
void get_prime(int n) {
for (int i = 2; i <= n; i++) {
if (!st[i]) prime[cnt++] = i;
for (int j = 0; prime[j] <= n / i; j++) {
st[prime[j] * i] = true;
if (i % prime[j] == 0) break;
}
}
}
void dfs(int u) {
if(u==n) {
for(int i=0; i<n; i++) cout<<path[i]<<" ";
cout<<endl;
return;
}
for(int i=1; i<=n; i++) {
if(!u||!ok[i]&&(s.count(path[u-1]+i)||s.count(abs(path[u-1]-i)))) {
path[u]=i;
ok[i]=true;
dfs(u+1);
ok[i]=false;
}
}
}
int main() {
cin>>n;
get_prime(N);
// for(int i=0;i<cnt;i++) cout<<prime[i]<<endl;
for(int i=0; i<cnt; i++) {
if(prime[i]!=2) s.insert(prime[i]);
}
// for(auto v:s) cout<<v<<endl;
dfs(0);
return 0;
}
然而打了表也没什么用,还是得手玩,找出构造的一般规律
1 4 7 2 5 8 3 6 9 12 15 10 13 16 11 14
发现每8个数为一周期:
1 4 7 2 5 8 3 6
一个周期的构造规律为:从第一个数开始,加3加3减5加3加3减5
9 12 15 10 13 16 11 14
不一定非得从1卡开始,从任何一个数开始都行,比如从8开始,8 11 14 9 12 15 10 13
所以我们先算出n最多可以有几个周期,即n/8,然后每个周期都按照以上规律填充
再单独填充那个不完整的周期,为方便填充,我们将那个不完整的周期先填充,比如是n%8等于7,那么我们单独填充1到7序列,然后从8开始填充完整的序列
现单独考虑n从1到7的序列
n=1 1 2
n=2 1 2 3
n=3 1 2 3 4
n=4 1 4 3 2 5
n=5 5 2 1 4 3 6
n=6 5 2 3 4 1 6 7
n=7 7 4 1 6 3 2 5 8
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<deque>
#include<cmath>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef long long ll;
const int N=1e5+10;
int a[N];
int n;
void solve() {
cin>>n;
int m=n%8;
if(m<=3) a[1]=1,a[2]=2,a[3]=3;
else if(m==4) a[1]=1,a[2]=4,a[3]=3,a[4]=2;
else if(m==5) a[1]=5,a[2]=2,a[3]=1,a[4]=4,a[5]=3;
else if(m==6) a[1]=5,a[2]=2,a[3]=3,a[4]=4,a[5]=1,a[6]=6;
else if(m==7) a[1]=7,a[2]=4,a[3]=1,a[4]=6,a[5]=3,a[6]=2,a[7]=5;
for(int i=m+1;i<=n;i+=8){
int x=i;
a[i]=x,a[i+1]=x+3,a[i+2]=x+6,a[i+3]=x+1,a[i+4]=x+4,a[i+5]=x+7,a[i+6]=x+2,a[i+7]=x+5;
}
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}