集美大学第十一届校程序设计竞赛(同步赛)

C.因子数小于等于4的个数

题目
多组,且没有“保证总数不超过。。。”,算下来只能是O(1)查找了。
如果一个一个筛因数,1e6*sqrt(1e6) 就会T掉,那当时就不知道怎么写了。最后发现了一个好的找因数的方法:
我们在外面创建两个数组。从1开始预处理我们可能要判断的数字。因数对应的就是倍数,我们第二维循环每次加j,就可以找i的倍数,也就是j的因数,就可以找出每个数字自身的因数个数。
我赛时想了很久。所以写,写题解也可以不让自己看手机,可能也是好处。

点击查看代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 10;
int a[1000005];
int b[1000005];
void is_(int n){
    for(int i=1;i<=n;i++){
        for(int j=i;j<=n;j+=i){
            a[j]++;
        }
    }
    for(int i=1;i<=n;i++){
        b[i]=b[i-1]+(a[i]<=4);
    }
}
void sovle()
{
    int l,r;
    cin>>l>>r;
    cout<<b[r]-b[l-1]<<endl;   
}

signed main()
{
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t = 1;
    is_(1000000);
    cin>>t;
    while (t--)
    {
        sovle();
    }
    return 0;
}

K. 数字三角形

题目

这个题赛事没想出来,我自己给自己下班了,还是不行……
一个数可以分解成多位 2^n 的和。利用这个性质来解决题目。

点击查看代码
#include<bits/stdc++.h>
#define endl '\n'
// #define int __int128
#define int long long 
using namespace std;
const int N = 1e5+10;
const int inf=1e18;
#define debug cout << "!!  !!debug!!  !!" << endl;
const int MAXN = 30005;
int n,m;
int pw[27];
void sovle(){
    cin>>n;
    vector<int>a(n+1);
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int mx= *max_element(a.begin()+1,a.begin()+n+1);
    int e=1;
    int cnt=0;
    while(e<=mx){
        e<<=1;
        cnt++;
    }//找出最大数字有多少二进制位。
    e>>=1;
    cnt--;//减去一位,因为最后要和其他位相加。
    pw[0]=1;
    for(int i=1;i<=26;i++){
        pw[i]=pw[i-1]*2;//把这些二进制位全都表示出来。
    }

    int len=cnt+1;//循环从0开始,len设为位数加一
    vector ans(cnt+2,vector<int>());//二维变长数组。
    for(int i=0;i<=len;i++){
        ans[i].resize(i+1,0);//填充大小
        ans[i][0]=0;//设置初始值
        for(int j=1;j<=i;j++){
            if(j&1){
                ans[i][j]=1;//如果当前是奇数位,就决定填充数字。
            }else{
                ans[i][j]=0;//偶数就填0
            }
        }
    }
    cout<<cnt+2<<endl;
    //第一行只有一个数字,那个数字必须要是0。
    //而2^n无法通过相加得到。只能再列一行。预备最大数就是2^n的情况。
    for(int i=0;i<len+1;i++){
        for(int j=0;j<ans[i].size();j++){
            if(j>0){
                cout<<" ";
            }if(ans[i][j]){
                cout<<pw[i-1];//每行都拿2^(i-1)赋值。
            }else{
                cout<<0;
            }
        }
        cout<<endl;
    }
    vector<string>res;
    for(int i=1;i<=n;i++){
        int pos=0;
        int y=0;
        int val=a[i];
        string now;
        for(int j=1;j<=len;j++){
            if(val>>(j-1)&1){//判断2进制位情况。
                if(ans[j][y]){
                    now+='L';//如果这一位是1并且当前位置有等效2的平方数的话,那么就直接下降,因为不是正规三角形
                    //(目前now的情况还停留在上一行!)
                }else{
                    now+='R';//当前这一位不存在所需2的平方数,那么这一位相邻的后一位一定是。
                    y++;//y++来改变当前位置。
                }
            }else{//反之,则与上面相反就好了。
                if(!ans[j][y]){
                    now+='L';
                }else{
                    now+='R';
                    y++;
                }
            }
        }
        res.push_back(now);
    }
    for(auto&s:res){
        cout<<s<<endl;
    }
}       
        
signed main(){	
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
    int t = 1; 
    
    // cin>>t;
    while (t --){
        sovle();
    }
    return 0;
}

F. 串

题目
字符串哈希
append函数是向string的后面追加字符或字符串。
首先将这个字符串在后面拷贝一份,将长度变成
​。

然后字符串哈希,于是我们寻找子串 [i,i+n) 的第 k 小的字符串即可。

那么如何快速比较两个字符串的大小呢?

· 因为有哈希值这个东西,考虑最长公共前缀 LCP
· 我们去二分 LCP 的长度,每次比较哈希值,
· 然后找到第一个不同的位置,
· 直接比较大小即可
这样我们就可以在 O(log n) 的时间内,比较两个字符串的大小。

点击查看代码
#include<bits/stdc++.h>
// #include<ext/pb_ds/assoc_container.hpp>
#define endl '\n'
// #define int __int128
#define int long long 
using namespace std;
const int N = 2e6+10;
const int inf=1e18;
#define debug cout << "!!  !!debug!!  !!" << endl;
const int MAXN = 30005;
typedef unsigned long long ull;
const int P = 131;
const int mod=998244353;
ull h[N], p[N];
int n,k;
string s;
inline ull find(int l, int r) {
    if(l>r) return 0;
    return h[r] - h[l - 1] * p[r - l + 1];
}
int id[N];
void sovle(){
    
    cin>>n>>k;
    cin>>s;
    s.append(s);
    //向后复制一下字符串。
    //因为要满足题目循环字符串条件。
    s=" "+s;
    p[0]=1;
    //预处理哈希值。
    for(int i=1;i<=2*n;i++){
        h[i]=(h[i-1]*P+s[i]);
        p[i]=(p[i-1]*P);
        id[i]=i;
    }

    //二分排列字符子串大小。
    sort(id+1,id+n+1,[&](int i,int j){
        int l=1,r=n;
        int ans=n;
        while(l<=r){
            int mid=(l+r)/2;
            if(find(i,i+mid-1)!=find(j,j+mid-1)){
                ans=mid;
                r=mid-1;
            }else{
                l=mid+1;
            }
        }
        if(ans==n){
            return i<j;
        }
        return s[i+ans-1]<=s[j+ans-1];
    });
    //找到第K个。
    cout<<s.substr(id[k],n)<<endl;
}       
        
signed main(){	
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); 
    int t = 1; 
    cin>>t;
    while (t --){
        sovle();
    }
    return 0;
}
posted @ 2025-01-25 19:59  miao-jc  阅读(20)  评论(0)    收藏  举报