首页 > 其他分享 >正睿csp-s7连测 day4

正睿csp-s7连测 day4

时间:2024-09-30 16:46:21浏览次数:1  
标签:int day4 s7 long mxn 连测 ll dp define

注:未登录正睿OI账号则看不了题目。

day 4

A

难度:蓝-紫
考虑贪心。
考虑优先选当前能连到了最小的点,但是这样会被样例卡疯。
考虑加一点策略。首先,若当前选到的点权大于其儿子的点权,那肯定把儿子也选上了,不然就不优了。
然后树上就会出现一些团。现在假设一个点下面连着两个团,考虑优先选那个团。

假设一个团A有两个点,点权为\((a_1,a_2)\);还有一个团B有三个点,点权为\((b_1,b_2,b_3)\)。
先选A再选B,结果为\(x_1=a_1*i+a_2*(i+1)+b_1*(i+2)+b_2*(i+3)+b_3*(i+4)\)。
先选B再选A,结果为\(x_2=b_1*i+b_2*(i+1)+b_3*(i+2)+a_1*(i+3)+a_2*(i+4)\)。
若\(x_1>x_2\),则有\(3(a_1+a_2)<2(b_1+b_2+b_3)\)。

推广一下,若A有 \(s_1\) 个点,点权和为 \(m_1\);B有 \(s_2\) 个点,点权和为 \(m_2\);则比较 \(s_1*m_2\) 和 \(s_2*m_1\) 的大小来判断优劣。
合并用并查集维护一下,就做完了。
时间复杂度约 \(O(kn\log n)\)

#include<bits/stdc++.h>
#define ll long long
#define mxn 30010
#define pii pair<int,int>
#define mp make_pair
using namespace std;
ll n,val[mxn],rot[mxn];
ll fath[mxn],ans,f[mxn];
vector<int> t[mxn];
struct node{
    ll num,val,sum,sze; 
};
bool operator <(const node& a,const node& b){
    return a.sum*b.sze>b.sum*a.sze;
}
bool operator >(const node& a,const node& b){
    return b<a;
}
bool operator !=(const node& a,const node& b){
    return (b.sum!=a.sum||b.val!=a.val||b.num!=a.num||b.sze!=a.sze);
}
priority_queue<node> q;
node tre[mxn];
    fath[u]=f;
    for(int i=0;i<t[u].size();i++){
        int v=t[u][i];
        if(v==f)continue;
        dfs(v,u);
    }
    return;
}
ll fnd(ll x){
    if(x==f[x])return x;
    return f[x]=fnd(f[x]);
}
void joinn(ll x,ll y){
    ll fx=fnd(x),fy=fnd(y);
    f[fx]=fy;
    return;
}
ll solve(int rt){
    memset(fath,0,sizeof(fath));
    dfs(rt,0);
    while(q.size())q.pop();
    for(int i=1;i<=n;i++)f[i]=i;
    for(int i=1;i<=n;i++)tre[i]=(node){i,val[i],val[i],1};
    for(int i=1;i<=n;i++)q.push((node){i,val[i],val[i],1});//num,val,sum,sze
    while(!q.empty()){
        node u=q.top();
        q.pop();
        if(u!=tre[u.num]||u.num==rt)continue;
        ll fa=fnd(fath[u.num]);
        joinn(u.num,fa);
        tre[fa].sum+=u.sum;
        tre[fa].val+=u.val+u.sum*tre[fa].sze;
        tre[fa].sze+=u.sze;
        q.push(tre[fa]);
    }
    return tre[rt].val;
}
int main(){
     ios::sync_with_stdio(0);
     cin.tie(0),cout.tie(0);
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        t[u].push_back(v);
        t[v].push_back(u);
    }
    for(int i=1;i<=n;i++)cin>>val[i]>>rot[i];
    for(int i=1;i<=n;i++)
        if(rot[i])
            ans=max(ans,solve(i));
    cout<<ans;
    return 0;
}

B

难度:黄-绿
傻逼数学题。
\(p<q\) 时直接输出 \(-1\);
\(p=q\) 时特判 \(1\),然后输出。
\(p>q\) 时考虑二分。
计算 \(0\sim mid\) 里不同非负整数的数量 \(x\)。这里有一个式子:\(x=\lceil \frac{(mid+1)q}{p}\rceil-1\),可以手推一下。
然后+1-1这种细节记得处理一下。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,p,q,k;
int main(){
    cin>>T;
    while(T--){
        cin>>p>>q>>k;
        if(p<q)cout<<-1<<endl;
        else if(p==q){
            if(k>1)cout<<-1<<endl;
            else cout<<0<<endl;
        }
        else{
            ll l=0,r=1e15;
            while(l<r){
                ll mid=(l+r)>>1;
                ll cnt=((mid+1)*q-1)/p;
                if(mid+1-cnt>=k)r=mid;
                else l=mid+1;
            } 
            cout<<r<<endl;
        }   
    }
    return 0;
}

C

难度:黄
弱智找规律题。
容易发现 \(>k\) 时方案数为 \((n-k)^{n-k}\)。\(\leq k\) 时暴搜记录就行了,方案数为 \(k^{k-1}\)。
还有一点要注意的是底数记得先取模。

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
ll n,k,di,mi;
ll quickpow(ll a,ll x){
    ll ret=1,base=a;
    while(x){
        if(x&1==1)ret=base*ret%mod;
        base=base*base%mod;
        x>>=1;
    }
    return ret;
}
int main(){
    cin>>n>>k;
    di=(n-k)%mod;
    cout<<quickpow(di,n-k)*quickpow(k,(k-1))%mod;
    return 0;
}

D

难度:蓝-紫
傻逼阅读理解题,内含OI特色长难句和谜语人题面。
题面翻译:给出一个长度为 \(m\) 的序列 \(a\),请你求出有多少种 \(1...n\) 的排列 \(S\),满足 \(a\) 是它的唯一最长上升子序列。
考虑状压dp。
对于每一位,有三种状态:不在排列 \(S\) 中;在排列 \(S\) 中且不在排列 \(a\) 中;在排列 \(S\) 中且在排列 \(a\) 中。搞三进制状压dp即可。

#include<bits/stdc++.h>//状压dp
#define ll long long
#define mxn3 14350000
#define mxn2 33000
using namespace std;
ll n,k,a[20],dp[mxn3];
ll mi[20],poww=1,ans;
bool vis[mxn2][20];
void init(){
    cin>>n>>k;
    for(int i=1;i<=k;i++){
        cin>>a[i];
        a[i]--;
    }
    mi[0]=1;
    for(int i=1;i<=n;i++)
        mi[i]=mi[i-1]*3,poww=poww*3;
    for(int i=0;i<(1<<n);i++){
        for(int j=0;j<n;j++){
            vis[i][j]=!((i>>j)&1);
            //如果第i状态不包含j则为1
            //意味着可以插数进去
            int pos=0;
            for(int l=1;l<=k;l++)
                if(a[l]==j)
                    pos=l;//找到序列中值为j的位置记作pos
            for(int l=1;l<pos;l++)
                if(!((i>>a[l])&1))
                    vis[i][j]=0;
                    //若该状态不包含a_1~a_pos-1中的所有数,则不能插下一个数(j)
        }
    }
    return;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    init();
    dp[0]=1;
    for(int i=0;i<poww;i++){
        if(!dp[i])continue;
        ll s=0,l=0,state=i,ok[20]={0},cnt=-1;
        //三进制记录状态,若为0则不在S中,若为2则只在S中,若为1则既在S中又在S1中
        for(int j=0;j<n;j++){
            if(state%3){//三进制记录每一种状态
                s|=(1<<j);
                if(state%3==1)ok[++cnt]=j;
                //id记录哪一位插过S1中的数
            }
            state/=3;
        }
        if(cnt>=k)continue;
        //大于等于k直接退了
        ok[cnt+1]=n+1;
        for(int j=0;j<n;j++){
            if(vis[s][j]==0)continue;
            //如果第j位能插数
            while(l<=cnt&&j>ok[l])l++;//找到下一个能插的数
            int nxt=i+mi[ok[l]]+mi[j];//x[l]移掉j插上
            dp[nxt]+=dp[i];
        }
        if(s==(1<<n)-1&&cnt==k-1)ans+=dp[i];
        //若S为给定序列,且cnt长为|a|
    }
    cout<<ans<<'\n';
    return 0;
}

标签:int,day4,s7,long,mxn,连测,ll,dp,define
From: https://www.cnblogs.com/nagato--yuki/p/18440778

相关文章

  • 梦熊 NOIP 13连测 #3
    A.赛事找规律找到了,可惜差一步,然后用了oies。欧拉定理:若\(gcd(a,m)=1\),则\(a^{\phi(m)}\equiv1(mod\m)\)。发现1和\(2n\)永远都不会动,并且当2归位时,整套牌也都归位了,所以先只考虑2的位置变化。如果\(n\)无线大,第\(i\)次操作后2的位置为\(2^i+1......
  • 卸载centos7自带的jdk
    卸载centos7自带的jdk问题描述在安装完centOS7虚拟机后,执行java-version,发现系统自带jdk8。因为我想使用jdk11,安装并配置环境变量后,环境变量仍显示为jdk8,所以需要卸载自带的jdk8。java-version解决方法1、查看自带的jdk包的包名称。rpm-qa|grepjdk2、切换到root......
  • Day4 C++(运算符重载,模板与容器)(友元函数,运算符重载,赋值运算符,string字符串类,模板)
    1.友元friend1.1概念(掌握)定义:类实现了数据的隐藏与封装,类的数据成员一般定义为私有成员,仅能通过类的成员函数才能读写。如果数据成员定义为公共的,则又破坏了封装性。但是某些情况下,需要频繁读写类的成员,特别是在对某些成员函数多次调用时,由于参数传递、类型检查和安全......
  • Docker安装教程是Centos7(有问题可留言)
    使用操作命令需要登陆root执行第一安装docker之前 检查linux内核  uname-r如果自己之前安装过需要卸载yumremovedockerdocker-commondocker-selinuxdocker-engin中途提示是否继续  选择y继续就行了如果不清楚可以执行一次这里如果提示 sudo:yum:......
  • 9.27 模拟赛(NOIP十三连测 #10)
    2024--梦熊&太戈--NOIP十三连测#10【订正】-比赛-梦熊联盟(mna.wang)复盘开T1。差分转化。模拟了一下样例感觉方案好像是唯一确定的,不需要贪心/DP。但不太能证。想了会感觉找不出反例。然后写完了。对拍没挂。用时不到\(30\)分钟。T2。\(m\le20\)且数据随机感觉很......
  • DAY4 收获
    输入与输出输出print()内置函数提供在控制台输出打印数据基本输出:print("helloworld!")   #输出结果:helloworld!输出变量:a=10b=20print(a,b)     #输出结果:1020改变输出分隔符(默认为空格):print("111","222","333",sep="_")  #输......
  • 【2021提高组十连测day7】a
    【2021提高组十连测day7】a题意:求每个点和其他所有点曼哈顿距离的平方之和。形式化地,求\(\sum_{j=1}^{n}(|x_i-x_j|+|y_i-y_j|)^2(1\lei\len)\)。对于每个点,我们把其他点分成四部分:左上、左下、右上、右下。四个部分可以通过旋转整个坐标系来解决。因此这里讲如何处理左上......
  • 【20zr提高组十连测day10】心
    【20zr提高组十连测day10】心首先不同的操作序列一定在某个时刻使数组内容不同,因此我们只需要统计合法的操作序列数量。一个合法的最终数组形如若干个\(1,M\),而且\(1,M\)之间可能有若干个\(x\),长度为\(n+1\)。造成这个数组的操作序列必须满足所有操作\(1,M\)按顺序排列,......
  • 【20zr提高组十连测day10】信
    【20zr提高组十连测day10】信给定\(n,m\),\(n,m\le10^5\),给定分别长度为\(n-1,m,n,m-1\)的单调不减的序列\(A,B,C,D\),然后形如该图建边:考虑到序列是递增的,对于除最左上角以外的每个点,每个点一定要选和自己相连的一条边才能形成一棵树。那么选择左边或上边一定是更优的,而且......
  • (Centos7/麒麟V10)服务器 Redis安装指南
    1.下载或上传安装包安装包官方下载地址:https://download.redis.io/releases/2.准备GCC编译环境查看gcc编译器版本:gcc-v若不存在则执行:yuminstall-ygcc或参考服务器gcc离线安装指南3.解压安装包并移至目标目录本文以redis-7.0.8.tar.gz安装包,部署路径/home/redis为......