周六训练赛2020江苏省省赛
🎈C - Cats
题意
有N个小猫(N小于1e5),每个猫的高度1~20,要求按身高猫排列,相同的身高的猫之间最矮的那只不得高于这两只猫,且相同的猫不能并排
思路
明显的构造题,2^20>1e5
可以看出身高为1的只能有1只,身高为2的只能在1的左右各一只,于是就想到如何构造,递归即可
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 1000000007
#define pb push_back
#define inf 0x3f3f3f3f
#define eps 0.00000001
const double pi = acos(-1);
using namespace std;
const int N = 2e5+10;
int a[N];
void dfs(int l,int r,int num){
if(l>r)return;
int mid=(l+r)>>1;
a[mid]=num;
if(l==r)return;
dfs(l,mid-1,num+1);
dfs(mid+1,r,num+1);
}
void solve(){
int n;
cin>>n;
dfs(1,n,1);
for(int i=1;i<=n;i++){
cout<<a[i]<<" ";
}cout<<endl;
}
int main(){
IOS;
solve();
return 0;
}
🎈D - Delete Prime
题意
给你一个1~n(n<1e6)长度,值为下标的数组,给你重新构造数组,构造如下:
先把数组里的下标为质数 or 1的按顺序放好,然后再把剩下的未排的数从小到大排序,再按下标为质数 or 1,直到排完
举个1~10的例子
1 2 3 5 7
4 6 8 9 10(1 2 3 4 5)
排完序为1 2 3 5 7 4 6 8 10 9
然后现在有两个操作
操作1,输入数组长度n和k,k表示数组值为k的下标
操作2,输入数组长度n和k,k表示数组下标为k的值
思路
前缀和,1~n有多少质数,然后dfs(n-qian[n]),这样为了查找排序操作需要最多几次,最大是80次,单纯的我以为是1e6除去1e6里面的质数个数,这里也要直接写80,不然铁tle9
再前缀和一下,表示这个数是第几轮第几个出去的
把n处理一下,变成几轮几个结束的状态,然后进行查找
操作一很简单,只要前缀和加一下即可,操作二,要进行for循环查找第几轮,二分查找第几个出去的
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 128
#define pb push_back
#define inf 0x3f3f3f3f
#define eps 0.00000001
const double pi = acos(-1);
using namespace std;
const int N = 1e6+10;
int qian[N],phi[N],p[N],cnt,vis[N];
int a[N][100],num[N],b[100];
void P(){
cnt=0;
for(int i=2;i<N;i++){
if(!vis[i])p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<N;j++){
vis[i*p[j]]=1;
if(i%p[j]==0){
break;
}
}
}
for(int i=1;i<N;i++) qian[i]=qian[i-1]+(!vis[i]);
}
int dfs(int n){
if(!vis[n]) return 1;
return 1+dfs(n-qian[n]);
}
int er(int pos,int k){
int l=1,r=N-1;
while(l<r){
int mid=(l+r)>>1;
if(a[mid][pos]>=k) r=mid;
else l=mid+1;
}
return l;
}
void solve(){
int t;
cin>>t;
while(t--){
int c,n,k;
cin>>c>>n>>k;
int now=n,len=0;
while(now){
b[++len]=qian[now];
now-=qian[now];
}
if(c==1){
int s=0;
for(int i=1;i<num[k];i++) s+=b[i];
cout<<(s+a[k-1][num[k]]+1)<<endl;
}else{
for(int i=1;i<=len;i++){
if(b[i]>=k){
cout<<er(i,k)<<endl;break;
}
k-=b[i];
}
}
}
}
int main(){
IOS;
P();
// int mx=-1;
for(int i=1;i<N;i++) num[i]=dfs(i),a[i][num[i]]=1;//mx=max(mx,num[i]);
for(int i=1;i<=80;i++){
for(int j=1;j<N;j++){
a[j][i]+=a[j-1][i];
}
}
solve();
return 0;
}
/*
*/
🎈H - Happy Morse Code
题意
有长度为N(N<1e5)的01字符串,M(M<26)个长度为5以内的s和t字符串,其中t为01字符串
问M个t字符串能不能替代01字符串,能替代多少种,答案取余128
思路
因为取余128,会有一种情况就是1和129都有可能输出happymorsecode,0和128有可能输出nonono
所以要标记是否达到128以上
第一想法是kmp跑,然后感觉时间铁超时,于是想到了dp
用map存一下t字符串的个数
动态转移方程:dp[i]=dp[i]+dp[i-t.len]*mp[t];
然后就标记是否有超过128就行了
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 128
#define pb push_back
#define inf 0x3f3f3f3f
#define eps 0.00000001
const double pi = acos(-1);
using namespace std;
const int N = 1e6+10;
int dp[N];
int vis[N];
void solve(){
int t;cin>>t;
while(t--){
mem(dp,0);
mem(vis,0);
int n,m;cin>>n>>m;
map<string,int>mp;
for(int i=0;i<m;i++){
string a,b;
cin>>a>>b;
mp[b]++;
}
string s;
cin>>s;
dp[0]=1;
int l=s.size();
s=' '+s;
for(int i=1;i<=l;i++){
for(int j=1;j<=5&&j<=i;j++){
string c=s.substr(i-j+1,j);//cout<<c<<" "<<(i-j+1)<<j<<endl;取第i-j+1后面j个字符串
if(mp[c]){
if(vis[i-j])vis[i]=1;
if(dp[i-j]*mp[c]>=128 || dp[i]+dp[i-j]*mp[c]>=128) vis[i]=1;
dp[i]=dp[i]+dp[i-j]*mp[c]%mod;dp[i]%=mod;
}
}
}
if(dp[l]==1 && !vis[l]){
cout<<"happymorsecode"<<endl;
}
else if(dp[l] || (!dp[l] && vis[l])){
cout<<"puppymousecat "<<dp[l]<<endl;
}
else{
cout<<"nonono"<<endl;
}
}
}
int main(){
IOS;
solve();
return 0;
}
/*
2
4 2
a 01
b 01
0101
5 1
a 1
11111
4
1
*/
🎈J - Just Multiplicative Inverse
题意
给一个递归程序F,问输入一个质素P,问F(X,P),X[1,P-1]平均要递归几次
F程序简化版
while(p%x>=1){
x=p%x;
}
思路
他们都是暴力过的,我暴力tle???
然后我想了很久,看出了一个线性关系,然后就打了个内表,过了
AC代码
#include<bits/stdc++.h>
#define endl '\n'
#define IOS ios::sync_with_stdio(false)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 1000000007
#define pb push_back
#define inf 0x3f3f3f3f
#define eps 0.00000001
const double pi = acos(-1);
using namespace std;
const int N = 1e6+10;
int a[N];
inline void solve(){
int n,t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
double ans=0;
for(int i=1;i<n;i++){
if(n%i==0){
a[i]=1;
}
else{
a[i]=a[n%i]+1;
}
}
for(int i=1;i<n;i++){
ans+=a[i];
}
printf("%.8f\n",ans/(n-1));
}
}
int main(){
solve();
return 0;
}