《2021牛客寒假算法基础集训营2》

H:签到。

F:可以发现长度就是1,2,3这些第一个不在自己i位置上的,他们自己的位置减去i。

长度找到后就去翻转验证能不能行即可。

本来应该是要双端队列去模拟这个过程的,暴力翻转复杂度肯定不够。

但是懒得写队列暴力了写了下过了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 5e6 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;
 
int a[N],pos[N],pre[N],nxt[N],rev[N];//rev = 1前换到后,rev2 = 后换到前
int main()
{
    int n;n = read();
    for(int i = 1;i <= n;++i) a[i] = read(),pos[a[i]] = i;
    int f = 0;
    for(int i = 1;i <= n;++i) if(a[i] != i) f = 1;
    if(f == 0) printf("yes\n1\n");
    else{
        int tag = 0,len,ok = 1;
        for(int i = 1;i <= n;++i){
            if(tag == 0){
                if(a[i] == i) continue;
                tag = 1;
                len = pos[i] - i + 1;
                for(int j = 1;j <= len / 2;++j) {
                    swap(a[i + j - 1],a[i + len - j]);
                }
            }
            else{
                if(a[i] == i) continue;
                else{
                    int to = i + len - 1;
                    if(a[to] != i) {
                        ok = 0;
                        break;
                    }
                    else{
                        for(int j = 1;j <= len / 2;++j){
                            swap(a[i + j - 1],a[i + len - j]);
                        }
                    }
                }
            }
           // printf("ronud %d\n",i);
           // for(int i = 1;i <= n;++i) printf("%d%c",a[i],i == n ? '\n' : ' ');
        }
        if(ok == 1){
            printf("yes\n");
            printf("%d\n",len);
        }
        else printf("no\n");
    }
      //system("pause");
    return 0;
}
View Code

I:线性筛。

因为直接存会爆longlong,中间取模的话又会导致答案不对。

所以我用了字符串来拼接,最后算值,string稍微有点慢,卡了卡常数才过了。

其实每个值只会爆一次筛选到,所以可以连父节点边,然后树上就可以dp统计贡献即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 4e6 + 5;
const int M = 5e6 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;
 
string f[N];
LL prime[N],tot = 0,ans = 0;
bool vis[N];
LL cal(string s){
    LL ans = 0;
    int len = s.size();
    for(int i = 0;i < len;++i){
        ans = (ans * 10 % Mod + (s[i] - '0')) % Mod;
    }
    return ans;
}
void init(int NN){
    for(int i = 2;i <= NN;++i){
        if(!vis[i]){
            f[i] = to_string(i);    
            prime[++tot] = i;
            ans = (ans + i) % Mod;
        }
        for(int j = 1;j <= tot && prime[j] * i <= NN;++j){
            vis[i * prime[j]] = 1;
            f[i * prime[j]] = to_string(prime[j]) + f[i];
            ans = (ans + cal(f[i * prime[j]])) % Mod;
            if(i % prime[j] == 0) break;
        }
    }
}
int main()
{
    int n;n = read();
    init(n);
    printf("%lld\n",ans);
      //system("pause");
    return 0;
}
View Code

J:这题其实不难,但是比赛中想错了。

首先,前面几个用f[i] = f[i - 1] + f[i - 2]来即可。

我们想要复杂度尽可能高,就需要让第一重循环i尽可能多,一开始就是这里没想清楚。

其实后面全插入1的话并且从2开始,这样就满足1 + 1 < f[i],无法构成三角形。这样可以前面的f[i]都无法满足。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 5e6 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;
 
LL f[N];
int main()
{
    int n;n = read();
    f[0] = 1,f[1] = 2;
    int up = 40;
    for(int i = 2;i <= n;++i){
        if(i <= up) f[i] = f[i - 1] + f[i - 2 ];
        else f[i] = 1;
    }
    for(int i = 1;i <= n;++i) printf("%d%c",f[i],i == n ? '\n' : ' ');
      //system("pause");
    return 0;
}
View Code

D:这题都往整除分块方向想了。

其实就是个找规律。

打表排序后可以发现,以$[\sqrt{n]}$为分界,一边就是1 ~ 这个值。一边就是n / 左边的值可以得到。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 5e6 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;
 
int main()
{
    int ca;ca = read();
    while(ca--) {
        int n,x;n = read(),x = read();
        int m = sqrt(n),sz;
        if(n / m == m) sz = 2 * m - 1;
        else sz = 2 * m;
        int ma = n / x;
        if(ma <= m) printf("%d\n",sz - ma + 1);
        else printf("%d\n",n / ma);
    }
      //system("pause"); 
    return 0;
}
View Code

E:一开始扫了一眼以为是贪心直接跳了。

其实是bfs,这题难在建图。

观察到y的范围很小,所以按y存,之后每个vector里按左边界升序,这样同高度的连边就很简单。

然后对于不同高度的就用双指针去维护,因为没有交叉的面积,所以双指针可以保证每个点基本只扫一遍,这样建图复杂度在O(n)。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 1e5 + 5;
const int M = 5e6 + 5;
const LL Mod = 1e9 + 7;
#define pi acos(-1)
#define INF 1e9
#define dbg(ax) cout << "now this num is " << ax << endl;
namespace FASTIO{
    inline LL read(){
        LL x = 0,f = 1;char c = getchar();
        while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
}
using namespace FASTIO;
 
struct Node{
    int L,r,id;
    bool operator < (const Node a)const{
        return L < a.L;
    }
};
vector<Node> vec[N];
vector<int> G[N];
int ans[N],n;
bool vis[N];
int bfs(){
    queue<int> Q;
    Q.push(1);
    ans[1] = 0;
    vis[1] = 1;
    while(!Q.empty()){
        int u = Q.front();
        Q.pop();
        if(u == n) return ans[u];
        for(auto v : G[u]){
            if(!vis[v]){
                vis[v] = 1;
                ans[v] = ans[u] + 1;
                Q.push(v);
            }
        }
    }
}
int main()
{
    n = read();
    for(int i = 1;i <= n;++i){
        int y,L,r;y = read(),L = read(),r = read();
        vec[y].push_back(Node{L,r,i});
    }
    for(int i = 0;i < N;++i) sort(vec[i].begin(),vec[i].end());
    for(int i = 0;i < N;++i){
        if(vec[i].size() == 0) continue;
        int st = 0;
        for(int j = 0;j < vec[i].size();++j){
            if(j < vec[i].size() - 1 && vec[i][j + 1].L == vec[i][j].r){//同y相邻连边
                int u = vec[i][j].id,v = vec[i][j + 1].id;
                G[u].push_back(v);
                G[v].push_back(u);
            }
            while(st < vec[i + 1].size() && vec[i + 1][st].r <= vec[i][j].L) st++;//先满足左边在里面
            while(st < vec[i + 1].size() && vec[i + 1][st].L < vec[i][j].r) {
                int u = vec[i][j].id,v = vec[i + 1][st].id;
                G[u].push_back(v);
                G[v].push_back(u);
                st++;
            }
            if(st != 0) st--;//上一层可能这个块横跨了多个块
        }
    }
    printf("%d\n",bfs());
      system("pause"); 
    return 0;
}
View Code

C:分类找规律构造。一开始以为后缀树之类的就没看。

G:离散化模拟,其实并不需要扫描线。看码力。

A:待补

B:待补。

 

posted @ 2021-02-04 10:21  levill  阅读(85)  评论(0编辑  收藏  举报