winter 2024 day2

bible- / 2024-01-25 / 原文

2023 中国大学生程序设计竞赛(CCPC)新疆赛区(重现赛

H数学

思路:有四平方和定理知道,任意正整数可表示为不超过四个整数的平方和

 并且n的范围为1e5,可以枚举出f(x)值为1、2、3、4的平方数组合情况。

也可以dp,f[i]=min(f[i],f[i-k*k]+1)

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=3e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-6;


void solve() {
    int n;
    cin >> n;
    vector<int> f(n + 5, INF);
    vector<int> g;
    for (int i = 1; i * i <= n; ++i)g.push_back(i * i);
    f[0] = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = 0; j < g.size(); ++j) {
            if (g[j] > i)break;
            f[i] = min(f[i], f[i - g[j]] + 1);
        }
    }
    int ans = 1;
    for (int i = 1; i <= n; ++i)ans = (ans * f[i]) % mod;
    cout << ans;
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

D在此同步

思路:想的相邻的两个数交换会让逆序对数改变一,那就找一个加一和一个减一的相邻对交换一下总逆序对数就不变,暴力找一遍就可以。后面抗体姐被自己整笑了,直接找个山峰或山谷(三个连续数),然后将其内部后移一位就行

...

 

BSang的奇妙冒险

思路:首先分析式子,因为是要从1到n,对于|i-j|整体看来就是n-1。对于|ai-aj|,这里题目求的是代价最小的方案数,那么很明显最小的代价是|a1-an|,直接一步到终点,因为在1到n的路途中出现山峰或山谷的话,只会增加代价,那么选择的ai应该是不递减或不递增的。问题就转化为求最长不下降子序列(a1<an)或最长不上升子序列(a1>an),翻转下后的求法就是一样的。

 

F任务安排

思路:首先没有序列a的话就是求拓扑排序,首先判断是否为拓扑序;其次,给每个点设置权值,求拓扑序时用优先队列即可。对于设置权值,把序列a按顺序递增给权值1、2、3....。还有一个问题,当序列a中的点,指向不在序列a中的点时可能会导致最后的拓扑序中序列a中的点不连续,那么在序列a中的点里,若其后缀为非序列a中的点,将其后缀的权值设为无穷大,这样就可以在当前拓扑序里已有序列a的点的情况下,优先选择权值小的,也就是在序列a中的点

 

E外接圆

思路:首先要知道的是三点确定圆,那么就来个n3的枚举确定圆,再来来个n的枚举判断剩余点是否在圆上,噢记得先去重了,记录每个点出现次数。还要注意所有点共线的情况,那就是两点确定一圆,找到出现次数最多的两点即可

...抄板子

 G动态二叉树

思路:考虑离线求,由于整个二叉树不会改变,可以先求出最终的二叉树。操作二问的是x右边的节点,其实就是bfs序中x的后继,可以先求出最终二叉树的所有节点对应的bfs序号。再重新依次操作,若是操作一,先找到该节点所在层数,在该层插入该节点的bfs序号,由于bfs序号是有序的,这里可以用set存储,二分找到该节点的后继。

#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=5e5+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
struct E{
    int op,p;
    char c;
};

void solve() {
    int n;
    cin>>n;
    vector<E>ve(n);
    vector<int>L(n+5),R(n+5),id(n+5),to(n+5);
    for(int i=0,idx=2;i<n;++i){
        cin>>ve[i].op;
        if(ve[i].op==1){
            cin>>ve[i].p>>ve[i].c;
            if(ve[i].c=='L')L[ve[i].p]=idx++;
            else R[ve[i].p]=idx++;
        }else{
            cin>>ve[i].p;
        }
    }
    queue<int>q;
    int idx=1;
    q.push(1);
    while(q.size()){
        int c=q.size();
        while(c--){
            int t=q.front();q.pop();
            to[idx]=t,id[t]=idx++;
            if(L[t])q.push(L[t]);
            if(R[t])q.push(R[t]);
        }
    }
    set<int>g[N+5];
    vector<int>d(n+5);
    g[0].insert(1);
    for(int i=0,now=2;i<n;++i){
        if(ve[i].op==1){
            int fd=d[ve[i].p];
            d[now]=fd+1;
            g[d[now]].insert(id[now++]);
        }else{
            auto t=g[d[ve[i].p]].lower_bound(id[ve[i].p]+1);
            int ans=-1;
            if(t!=g[d[ve[i].p]].end())ans=to[*t];
            cout<<ans<<'\n';
        }
    }
}

signed main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int t=1;
//    cin>>t;
    while(t--){
        solve();
    }
    return 0;
}
View Code

 

J子段和二象性

思路:搞成图来想,(但是还是不懂T^T),,那就要有点和关系,看原数组的前缀和数组,在满足条件的情况下,Si<Si+n,Si<Si-m(因为每n个数和为正,每m个数和为负),那么点就看成是Si,根据大小关系,Si指向Si+n,Si指向Si-m,找到非环的最长的链。

对于n=2、m=3,可以这样构造,从0开始,S0→S2→S4→S1→S3→S0,直到构成了环为止,这时候的最大长度为最大编号减一(不懂)

打表可以发现答案为n+m-gcd(n,m)-1

证明