CSUST2021集训队选拔赛题解

本场难度:
简单:A,B,E,H,K
中等:C,D,F,G,I

签到题又双叒叕来了

线段树模板题,在建树时,把奇数位的数设为正数,偶数位置的数设为负数,在查询区间和的时候,判断 l l l 位置是正还是负,如果为负,只需要把区间和乘上-1即可。
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const int eps=1e-6;
int n,q;
int a[maxn];
ll tree[maxn<<2][2]; //0 偶数 1// 奇数
void build(int node,int l,int r){
    
    
    if(l==r){
    
    
        if(l%2==0){
    
    
            tree[node][0]=a[l];
            tree[node][1]=0;
        }else{
    
    
            tree[node][1]=a[l];
            tree[node][0]=0;
        }
        return ;
    }
    int mid=(l+r)/2;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    tree[node][0]=tree[node<<1][0]+tree[node<<1|1][0];
    tree[node][1]=tree[node<<1][1]+tree[node<<1|1][1];
}
void update(int node,int pos,int val,int l,int r){
    
    
    if(l==r){
    
    
        if(l%2==0){
    
    
            tree[node][0]=val;
        }else{
    
    
            tree[node][1]=val;
        }
        return ;
    }
    int mid=(l+r)/2;
    if(mid>=pos) update(node<<1,pos,val,l,mid);
    else         update(node<<1|1,pos,val,mid+1,r);
    tree[node][0]=tree[node<<1][0]+tree[node<<1|1][0];
    tree[node][1]=tree[node<<1][1]+tree[node<<1|1][1];
}
ll query(int node,int l,int r,int L,int R,int id){
    
    
    if(L<=l&&r<=R){
    
    
        return tree[node][id];
    }
    int mid=(l+r)/2;
    ll sum=0;
    if(mid>=L) sum+=query(node<<1,l,mid,L,R,id);
    if(mid<R)  sum+=query(node<<1|1,mid+1,r,L,R,id);
    return sum;
}
signed main(){
    
    
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
    
    
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    for(int i=1,opt,l,r,pos,val;i<=q;i++){
    
    
        scanf("%d",&opt);
        if(opt==1){
    
    
            scanf("%d%d",&l,&r);
            ll ans=query(1,1,n,l,r,1)-query(1,1,n,l,r,0);
            if(l%2==0) ans=-ans;
            printf("%lld\n",ans);
        }else{
    
    
            scanf("%d%d",&pos,&val);
            update(1,pos,val,1,n);
        }
    }
    return 0;
}

大毒瘤

一维数组 f [ h i g h ] = l i f e f[high]=life f[high]=life

循环从d到0

如果这个高度的生命值不小于这个能源丢下来的时间

如果 高度加这个能源的高度不小于d,就输出这个能源丢下来的时间

不然 这个高度加这个能源的高度 的生命值=max(d~0的生命值),即不吃能源用它来堆,此时高度+=这个能源的高度

这个高度的生命值+=吃这个能源增长的生命值,即吃能源,此时高度不变

最后输出高度为0的生命值,即出不去存活的最长时间
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=1e5+5;
struct node
{
    
    
    int t;
    int f;
    int h;
}g[105];
int dp[1000];
bool cmp(node a,node b)
{
    
    
    return a.t<b.t;
}
int main()
{
    
    
    int d,n;
    cin>>d>>n;
    int sum=10;
    for(int i=1;i<=n;i++)
    {
    
    
        cin>>g[i].t>>g[i].f>>g[i].h;
        sum+=g[i].f;
    }
    sort(g+1,g+1+n,cmp);
    memset(dp,-1,sizeof dp);
    dp[0]=10;
    for(int i=1;i<=n;i++)
    {
    
    
        for(int j=d;j>=0;j--)
        {
    
    
            if(dp[j]>=g[i].t)
            {
    
    
                if(j+g[i].h>=d)
                {
    
    
                    cout<<g[i].t<<endl;
                    return 0;
                }
                dp[j+g[i].h]=max(dp[j+g[i].h],dp[j]);
                dp[j]+=g[i].f;
            }
        }
    }
    cout<<dp[0]<<endl;
}

小YY闯地牢

C a b C_a^b Cab = b ! a ! ( a − b ) ! \frac {b!}{a! (a-b)!} a!(ab)!b!

对这个式子取 l o g log log会变成: l o g b − l o g a − l o g ( a − b ) logb- loga-log(a-b) logblogalog(ab)

因为花费是乘起来,但是再取完 l o g log log后,就会变成加起来,这样就变成普通的最短路,求组合数取模要么dp预处理,要么求逆元。
代码:

#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int>pii;
const int MAXN=2e5+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
int head[MAXN];
int vis[MAXN];
ll dis[MAXN];
double pre[MAXN];
int cnt;
ll fac[MAXN];
double dp[MAXN];
void cal()
{
    
    
    fac[0]=1;
    for(int i=1; i<MAXN; i++)
        fac[i]=fac[i-1]*i%mod;
}
ll qpow(ll a,ll b)
{
    
    
    ll ans=1;
    for(; b; b>>=1,a=a*a%mod)
        if(b&1)
            ans=ans*a%mod;
    return ans;
}

ll C(ll n,ll m)
{
    
    
    if(n<m)
        return 0;
    return fac[n]*qpow(fac[n-m]*fac[m]%mod,mod-2)%mod;
}
struct edge
{
    
    
    int to;
    double cost;
    ll w;
    int next;
}e[MAXN*2];
struct node
{
    
    
    int pos;
    double val;
    friend bool operator<(node a,node b)
    {
    
    
        return a.val>b.val;
    }
};
void add(int u,int v,ll w,double cost)
{
    
    
    e[cnt].to=v;
    e[cnt].w=w;
    e[cnt].cost=cost;
    e[cnt].next=head[u];
    head[u]=cnt++;
}
void solve(int s,int k,int n)
{
    
    
    for(int i=1;i<=n;i++)
    {
    
    
        vis[i]=0;
        pre[i]=1e16;
        dis[i]=1e16;
    }
    priority_queue<node> q;
    q.push(node{
    
    s,0});
    pre[s]=0;
    dis[s]=k;
    while(!q.empty())
    {
    
    
        node now=q.top();
        q.pop();
        //cout<<now.pos<<endl;
        if(vis[now.pos]) continue;
        vis[now.pos]=1;
        for(int i=head[now.pos];i!=-1;i=e[i].next)
        {
    
    
            int v=e[i].to;
            //cout<<v<<" "<<pre[v]<<" "<<now.val+e[i].cost<<endl;
            if(pre[v]>now.val+e[i].cost)
            {
    
    
                pre[v]=now.val+e[i].cost;
                q.push(node{
    
    v,pre[v]});
                dis[v]=dis[now.pos]*e[i].w%mod;
            }
        }
    }
}
int main()
{
    
    
    cal();
    for(int i=1;i<=1e3;i++)
    {
    
    
        dp[i]=dp[i-1]+log(i);
    }
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
        int n,m,k,st,ed;
        scanf("%d%d%d%d%d",&n,&m,&k,&st,&ed);
        cnt=0;
        for(int i=1;i<=n;i++)
        {
    
    
            head[i]=-1;      
        }
        for(int i=1;i<=m;i++)
        {
    
    
            int u,v,a,b;
            scanf("%d%d%d%d",&u,&v,&a,&b);
            add(u,v,C(a,b),(dp[a]-dp[a-b])-dp[b]);
        }
        solve(st,k,n);
        if(dis[ed]>=1e16) printf("-1\n");
        else printf("%lld\n",dis[ed]);
    }
}

温暖人心

二分最高等级,如果金币足够到达该等级,那么 l = m i d + 1 l=mid+1 l=mid+1,否则 r = m i d − 1 r=mid-1 r=mid1
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=1e5+5;
ll n[5],e[5];ll m,p,c,s;
bool check(ll mid)
{
    
    
    ll res=0;
    if(p/n[1]<mid){
    
    
        res+=(mid*n[1]-p)*e[1];
    }
    if(c/n[2]<mid){
    
    
        res+=(mid*n[2]-c)*e[2];
    }
    if(s/n[3]<mid){
    
    
        res+=(mid*n[3]-s)*e[3];
    }
    return res<=m;
}
int main()
{
    
    
    int t;
    cin>>t;
    while(t--){
    
    
        cin>>m>>p>>c>>s;
        for(int i=1;i<=3;i++){
    
    
            cin>>n[i];
        }
        for(int i=1;i<=3;i++){
    
    
            cin>>e[i];
        }
        ll d=min(min(p/n[1],c/n[2]),s/n[3]);
        ll l=d,r=1e12;
        ll ans;
        while(l<=r){
    
    
            ll mid=(l+r)>>1;
            if(check(mid)){
    
    
                ans=mid;
                l=mid+1;
            }
            else{
    
    
                r=mid-1;
            }
        }
        printf("%lld\n",ans);
    }
}

我才是签到题

先用并查集求出每一个联通块,后面就是普通的01背包问题。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=1e5+5;
int fa[MAXN];
ll num1[MAXN],num2[MAXN];
std::vector<int> v;
ll dp[MAXN];
int finder(int x)
{
    
    
    if(fa[x]==x) return x;
    else return fa[x]=finder(fa[x]);
}
void combine(int x,int y)
{
    
    
    x=finder(x);
    y=finder(y);
    if(x!=y){
    
    
        fa[x]=y;
        num1[y]+=num1[x];
        num2[y]+=num2[x];
    }
}
int main()
{
    
    
    int n,m,p;
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=n;i++){
    
    
        cin>>num1[i]>>num2[i];
    }
    for(int i=1;i<=m;i++){
    
    
        int x,y;
        cin>>x>>y;
        combine(x,y);
    }
    for(int i=1;i<=n;i++){
    
    
        if(finder(i)==i&&p>=num2[i]){
    
    
            v.push_back(i);
        }
    }
    for(auto i:v){
    
    
        for(int j=p;j>=num2[i];j--){
    
    
            dp[j]=max(dp[j],dp[j-num2[i]]+num1[i]);
        }
    }
    printf("%lld\n",dp[p]);
}

暴力ac题

状压 d p dp dp,用1表示有士兵,0表示没有士兵,那么可以用二进制去表示出所有状态,再看这些二进制是否不存在连续相邻的1,并且当前状态与前状态的&值必须为0,并且1必须放在平原上。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int>pii;
const int MAXN=5e2+500;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
int a[15][15];
int b[15];
ll dp[15][1<<13];
int rightt[1<<13];
bool judge1(int i)
{
    
    
    if(((i<<1)&i)==0) return true;
    else return false;
}
bool judge2(int i,int j)
{
    
    
    if(i&j) return false;
    else return true;
}
int main()
{
    
    
    int n,m;
    int t;
    scanf("%d",&t);
    while(t--)
    {
    
    
    	scanf("%d%d",&n,&m);
        memset(b,0,sizeof b);
        for(int i=1;i<=n;i++)
        {
    
    
            for(int j=1;j<=m;j++)
            {
    
    
                cin>>a[i][j];
                a[i][j]^=1;
                b[i]=b[i]*2+a[i][j];
            }
        }
        int cnt=0;
        for(int i=0;i<=(1<<m)-1;i++)
        {
    
    
            if(judge1(i))
            {
    
    
                rightt[++cnt]=i;
            }
        }
        memset(dp,0,sizeof dp);
        for(int i=1;i<=cnt;i++)
        {
    
    
            if(judge2(rightt[i],b[1]))
            {
    
    
                dp[1][rightt[i]]=1;
                //cout<<rightt[i]<<endl;
            }
        }
        for(int i=2;i<=n;i++)
        {
    
    
            for(int j=1;j<=cnt;j++)
            {
    
    
                if(!judge2(rightt[j],b[i])) continue;
                for(int k=1;k<=cnt;k++)
                {
    
    
                    if(dp[i-1][rightt[k]]==0) continue;
                    if(judge2(rightt[j],rightt[k]))
                    {
    
    
                        dp[i][rightt[j]]=(dp[i][rightt[j]]+dp[i-1][rightt[k]])%mod;
                    }       
                }
            }
        }
        ll ans=0;
        for(int i=1;i<=cnt;i++)
        {
    
    
            ans=(ans+dp[n][rightt[i]])%mod;
        }
        printf("%lld\n",ans);
    }
}

排序

用线段树维护区间和,即1的数量,那么在每次操作时,先求出区间的1的数量,因为排序,所以区间就能分为两段,一段为0,一段为1,那么就是线段树区间修改值即可。
代码:

#include<bits/stdc++.h>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int>pii;
const int MAXN=5e4+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
struct Node
{
    
    
    int l,r;
    int lazy;
    int sum;
}node[MAXN<<2];
int a[MAXN];
void push_down(int num)
{
    
    
    if(node[num].lazy==-1) return;
    node[num<<1].lazy=node[num<<1|1].lazy=node[num].lazy;
    node[num<<1].sum=(node[num<<1].r-node[num<<1].l+1)*node[num].lazy;
    node[num<<1|1].sum=(node[num<<1|1].r-node[num<<1|1].l+1)*node[num].lazy;
    node[num].lazy=-1;
}
void push_up(int num)
{
    
    
    node[num].sum=node[num<<1].sum+node[num<<1|1].sum;
}
void build(int l,int r,int num)
{
    
    
    node[num].l=l;
    node[num].r=r;
    node[num].lazy=-1;
    if(l==r)
    {
    
    
        node[num].sum=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
    node[num].sum=node[num<<1].sum+node[num<<1|1].sum;
}
void updata(int l,int r,int val,int num)
{
    
    
    if(node[num].l>=l&&node[num].r<=r)
    {
    
    
        node[num].lazy=val;
        node[num].sum=(node[num].r-node[num].l+1)*val;
        return;
    }
    push_down(num);
    int mid=(node[num].l+node[num].r)>>1;
    if(l<=mid)
    {
    
    
        updata(l,r,val,num<<1);
    }
    if(r>mid)
    {
    
    
        updata(l,r,val,num<<1|1);
    }
    push_up(num);
}
int query(int l,int r,int num)
{
    
    
    if(node[num].l>=l&&node[num].r<=r)
    {
    
    
        return node[num].sum;
    }
    push_down(num);
    int ans=0;
    int mid=(node[num].l+node[num].r)>>1;
    if(l<=mid)
    {
    
    
        ans+=query(l,r,num<<1);
    }
    if(r>mid)
    {
    
    
        ans+=query(l,r,num<<1|1);
    }
    return ans;
}
int main()
{
    
    
    int n,q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
    
    
        scanf("%d",&a[i]);
    }
    build(1,n,1);
    int op,l,r;
    while(q--)
    {
    
    
        scanf("%d%d%d",&op,&l,&r);
        int sum=query(l,r,1);
        int len=r-l+1-sum;
        if(op==0)
        {
    
    
            if(l<=l+len-1) updata(l,l+len-1,0,1);
            if(l+len<=r) updata(l+len,r,1,1);
        }
        else
        {
    
    
            if(l<=l+sum-1) updata(l,l+sum-1,1,1);
            if(l+sum<=r) updata(l+sum,r,0,1);
        }
    }
    for(int i=1;i<=n;i++)
    {
    
    
        cout<<query(i,i,1)<<" ";
    }
}

Thebest的数学题​

所有数都可以拆成素数相乘,用素数筛求出 1 e 6 1e6 1e6以内所有的素数,再对1到 n n n 所有数质因子分解,这样可以求出 n ! n! n! 质因子分解后每个素数有多少次幂,再将所有次幂+1相乘即可,比如 24 = 2 ∗ 2 ∗ 2 ∗ 3 = 2 3 ∗ 3 1 24=2*2*2*3=2^3*3^1 24=2223=2331 ,那么答案就是 ( 3 + 1 ) ∗ ( 1 + 1 ) = 8 (3+1)*(1+1)=8 (3+1)(1+1)=8
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int>pii;
const int MAXN=1e6+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
int prime[MAXN],cnt;
int isprime[MAXN];
int vis[MAXN];
void getprime(int n)
{
    
    
    for(ll i=2;i<=n;i++)
    {
    
    
        if(!isprime[i])
        {
    
    
            prime[++cnt]=i;
            isprime[i]=i;
        }
        for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
        {
    
    
            isprime[i*prime[j]]=prime[j];
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    
    
    getprime(1e6);
    int n;
    scanf("%d",&n);
    if(n==1){
    
    
        cout<<1<<endl;
        return 0;
    }
    for(int i=2;i<=n;i++){
    
    
        int temp=i;
        while(temp!=1){
    
    
            vis[isprime[temp]]++;
            temp/=isprime[temp];
        }
    }
    ll ans=1;
    for(int i=1;i<=cnt;i++){
    
    
        if(vis[prime[i]]){
    
    
            ans=ans*(vis[prime[i]]+1)%mod;
        }
    }
    cout<<ans<<endl;
}

小b想要知道

a ⨁ b = n a \bigoplus b=n ab=n 可以变为 a = n ⨁ b a=n \bigoplus b a=nb ,

n n n 转成二进制,可以发现,因为 a a a要比 b b b 小,那么 n n n 的最高位的1 和 b b b 最高位的1 位置必须一样,否则 a a a就会比 b b b 大,

已经保证 a ≤ b a \leq b ab , 那么其实就是求 b b b 有多少取值,因为 b < n b < n b<n ,所以 b的取值就是 n − 1 − 2 x + 1 n-1-2^x+1 n12x+1 ,x为n最高位的1的位置
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int mod=1e9+7;
const int MAXN=1e6+5;
int main()
{
    
    
    int t;
    cin>>t;
    while(t--)
    {
    
    
        int n;
        cin>>n;
        int temp=n;
        int cnt=0;
        while(n)
        {
    
    
            cnt++;
            n>>=1;
        }
        int x=1<<(cnt-1);
        int ans=(temp-1)-x+1;
        printf("%d\n",ans);
    }
}

会长认证签到题

a ⋅ b = c a \cdot b=c ab=c 可以推出 a ⋅ b a \cdot b ab % m o d mod mod= c c c % m o d mod mod

即( a a a% m o d mod mod ⋅ \cdot b b b% m o d mod mod)% m o d mod mod= c c c% m o d mod mod

因为一个整数可以表示成 a = x ⋅ 1 0 n + y ⋅ 1 0 n − 1 + z ⋅ 1 0 n − 2 + . . . . . a=x \cdot 10^n+y \cdot 10^{n-1}+z \cdot 10^{n-2}+..... a=x10n+y10n1+z10n2+.....

那么 a a a m o d mod mod取模的值就很容易求出来了,只需枚举星号是什么数,算出三个数取模后的值,看相乘是否相等即可。

代码:

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e6+5,inf=0x3f3f3f3f,mod=998244353;
const double eps=1e-10;
int d1,d2,d3;
char a[maxn],b[maxn],c[maxn<<1];
ull sum1,sum2,sum3;
ull cal(int x){
    
    
    sum3=0;
    for(int i=1;i<=d3;i++){
    
    
        if(c[i]=='*'){
    
    
            sum3=(sum3*10+x)%mod;
        }else{
    
    
            sum3=(sum3*10+c[i]-'0')%mod;
        }
    }
    return sum3;
}
signed main(){
    
    
    scanf("%d%d%d",&d1,&d2,&d3);
    scanf("%s %s %s",a+1,b+1,c+1);
    for(int i=1;i<=d1;i++){
    
    
        sum1=(sum1*10+a[i]-'0')%mod;
    }
    for(int i=1;i<=d2;i++){
    
    
        sum2=(sum2*10+b[i]-'0')%mod;
    }
    for(int i=0;i<=9;i++){
    
    
        if(sum1*sum2%mod==cal(i)){
    
    
            printf("%d\n",i);
            break;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45755679/article/details/114709558
今日推荐