练习记录-河南2020省赛补题(ABCE)

A 班委竞选

比手速直接写掉了(

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
struct stu{
    int id,zw,p;
}S[MAXN]; 
bool bj(stu a,stu b){
    if(a.zw!=b.zw) return a.zw<b.zw;
    else if(a.p!=b.p) return  a.p>b.p;
    else return a.id<b.id;
}
void solve(){
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>S[i].zw>>S[i].p;
        S[i].id=i;
    }
    sort(S+1,S+n+1,bj);
    int cnt=1;
    for(int i=1;i<=n;i++){
        if(S[i].zw==cnt) {
            cout<<S[i].id<<" ";
            cnt++;
        }
    }
}
int main(){
    solve();
}
View Code

B 广告投放(dp)

这是补的 考场上太慌,转移方程写的一拖四,根本写不出来

考后看了别人的代码,应该以人数作为转移方程的i值,由于转移只会用到上一层,用01数组可以优化

转移方程:dp[i%2][c[j]]=max(dp[i%2][c[j]],dp[(i-1)%2][c[j]]) 表示不在这集播广告的状态

        dp[i%2][c[j]/w[i]]=max(dp[i%2][c[j]/w[i]],dp[(i-1)%2][c[j]]+v[i]*c[j]) 表示在这集播广告的状态

其中 c[i]为处理后的人数数组 如果直接遍历m 会超时 而m经过整除 只会到达某几个数 如5 无法到达3和4 因此可以通过处理减少计算次数

然后就好了

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
#define int long long
int vis[MAXN],dp[2][MAXN],c[MAXN],v[MAXN],w[MAXN];
int lowbit(int x){ return x&-x; }
int gcd(int x,int y){int k=0; if(x<y){k=x;x=y;y=k;}while(x%y!=0){k=x%y;x=y;y=k;}return y;}
ll _power(ll a,int b){ll ans=1,res=a;while(b){if(b&1) ans=ans*res%mod;res=res*res%mod;b>>=1;}return ans%mod;}
void solve(){
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>v[i];
    for(int i=1;i<=n;i++) cin>>w[i];
    //处理人数的可能性减小计算次数 
    //使用01数组优化 
    int cnt=0;
    c[++cnt]=0;
    //处理出所有的可能性 大幅降低时间 
    for(int i=1;i<=m;i++){
        if(!vis[m/i]){
            vis[m/i]=1;
            c[++cnt]=m/i;
        }
    }
    //sort(c+1,c+1+cnt);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=cnt;j++){
            dp[i%2][c[j]]=max(dp[i%2][c[j]],dp[(i-1)%2][c[j]]);//从原始数据转移 
            dp[i%2][c[j]/w[i]]=max(dp[i%2][c[j]/w[i]],dp[(i-1)%2][c[j]]+v[i]*c[j]);
            //处理选择后的数据  
        }
    }
    int ans=0;
    for(int i=0;i<=m;i++) ans=max(ans,dp[n%2][i]);
    cout<<ans;
}
signed main(){
   close;
    solve();
}
View Code

C 我得重新集结部队

模拟 就直接模拟就行了 但是要注意 不要拿sqrt算距离 直接ll算平方和,不然会出现精度问题 wa11个样例

我是拿sort排序自带算出距离最小的 第一次这么写sort的函数 没想到真的可以

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 3e5+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
const double eps =1e-6;
#define int long long
struct muxi{
    int x,y,h,id,die;
}M[MAXN];
int xx,yy,ans[MAXN];
bool bj(muxi a,muxi b){
    int ax=a.x,ay=a.y,bx=b.x,by=b.y;
    ll disa=(ax-xx)*(ax-xx)+(ay-yy)*(ay-yy);
    ll disb=(bx-xx)*(bx-xx)+(by-yy)*(by-yy);
    if(a.h<=0||b.h<=0){
        return a.h>b.h; 
    } 
    else if(disa!=disb){
        return disa<disb;
    }
    else return a.id<b.id;
}
int cnt=0;
void solve(){
    int n;cin>>n;
    for(int i=1;i<=n;i++){
        int op;cin>>op;
        if(op==1){
            int x,y,h;
            cin>>x>>y>>h;
            M[cnt].id=i;M[cnt].h=h,M[cnt].x=x,M[cnt].y=y;
            cnt++;
        }
        else{
            int r,atk;
            cin>>xx>>yy>>atk>>r;
            sort(M,M+cnt,bj);
            int ax=M[0].x,ay=M[0].y;
            int flag=0;
            for(int j=0;j<cnt;j++){
                int bx=M[j].x,by=M[j].y;
                if((ax-bx)*(ax-bx)+(ay-by)*(ay-by)<=1LL*r*r){
                    if(M[j].h>0)
                    M[j].h-=atk*3;
                    if(M[j].h>0) ans[i]=1;
                    else ans[M[j].id]=1;
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        if(ans[i]==1) cout<<"NO\n";
        else cout<<"YES\n";
    }
}
signed main(){
    solve();
}
View Code

E 发通知

补的 考场上一直拿区间相交在模拟 但是这题对于每一个线段,从1-1e9遍历 遇到头节点就^w,遇到尾节点再异或一遍 因此把每个点首位拆开进行排序 然后记录点的了,类型

遍历所有的点 记录ans与cnt cnt>=k就取max 即可得出答案

还要注意如果有同一点的 要先一起处理完再计算

#include<bits/stdc++.h>
#define close     std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const ll MAXN = 2e6+7;
const ll mod =1e9+7;
const ll inf =0x3f3f3f3f;
const ll INF =0x3f3f3f3f3f3f3f3f;
int f[MAXN];
struct node{
    int t,w,x;
}N[MAXN];
bool bj(node a,node b){
    return a.x<b.x;
}
int lowbit(int x){ return x&-x; }
int gcd(int x,int y){int k=0; if(x<y){k=x;x=y;y=k;}while(x%y!=0){k=x%y;x=y;y=k;}return y;}
ll _power(ll a,int b){ll ans=1,res=a;while(b){if(b&1) ans=ans*res%mod;res=res*res%mod;b>>=1;}return ans%mod;}
void solve(){
    int n,m;cin>>n>>m;
    for(int i=0;i<n;i++){
        int x,y,w;cin>>x>>y>>w;
        N[i*2].x=x,N[i*2].t=1,N[i*2].w=w;
        N[i*2+1].x=y+1,N[2*i+1].t=-1,N[i*2+1].w=w;
    }
    map<int,int> sz;
    sort(N,N+2*n,bj);
    int maxs=-1,ans=0,cnt=0;
    for(int i=0;i<2*n;i++){
        cnt+=N[i].t;
        ans^=N[i].w;
        if(cnt>=m&&N[i].x!=N[i+1].x) maxs=max(ans,maxs);
    }
    cout<<maxs;
}
int main(){
    solve();
}
View Code

后续继续补题将更新

 

posted @ 2023-03-13 08:00  xishuiw  阅读(35)  评论(0)    收藏  举报