noip模拟57[水题]

noip模拟57(联考) solutions

这题说实话是真的水。。。。。

T1 ip

这个就是直接判断就好了,

注意前导零和多'.'的情况,我WA了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=35;
char ch[N];
int n,sum[10],m=1;
signed main(){
    freopen("ip.in","r",stdin);
    freopen("ip.out","w",stdout);
    scanf("%s",ch+1);
    n=strlen(ch+1);
    bool flag=false;
    int su=0;
    if(ch[1]<'0'||ch[1]>'9')flag=true;
    if(ch[n]<'0'||ch[n]>'9')flag=true;
    fo(i,1,n){
        if(ch[i-1]>='0'&&ch[i-1]<='9'&&(ch[i]<'0'||ch[i]>'9'&&i>1))m++;
        if(ch[i]>='0'&&ch[i]<='9'){
            if(sum[m]==0&&ch[i]=='0')flag=true;
            sum[m]=sum[m]*10+ch[i]-'0';
            if(sum[m]>255)sum[m]=255,flag=true;
            //cout<<i<<" "<<m<<endl;
        }
        else if(ch[i]=='.'&&su<3){su++;continue;}
        else flag=true;
        if(ch[i]=='.'&&m==1)flag=true;
    }
    if(flag){
        printf("NO\n");
        for(int i=1;i<=3;i++)printf("%d.",sum[i]);printf("%d",sum[4]);
    }
    else printf("YES\n");
}

T2 删字符

这个直接能向前匹配就向前匹配

因为P啥都能删

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=10005;
int n,nxt[N],ans;
char ch[N];
bool vis[N];
signed main(){
    freopen("apstr.in","r",stdin);
    freopen("apstr.out","w",stdout);
    scanf("%s",ch+1);
    n=strlen(ch+1);ans=n;
    fo(i,1,n){
        if(ch[i]=='A'){nxt[i+1]=i;continue;}
        if(!nxt[i])nxt[i+1]=i;
        else ans-=2,nxt[i+1]=nxt[nxt[i]];
    }
    printf("%d",ans);
}

T3 定义类

直接用\(bitset\)记录它的所有祖先,暴力\(\mathcal{O(n^4)}\)就行了

因为\(bitset\)有时间优化,所以直接过了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1005;
int n,m,ji[N];
string now,sb,bl[N];
map<string,int> mp;
bitset<N> bit[N];
signed main(){
    freopen("class.in","r",stdin);
    freopen("class.out","w",stdout);
    cin>>n;
    fo(i,1,n){
        m=0;cin>>now>>sb;
        while(true){
            cin>>bl[++m];
            if(bl[m][0]==';'){m--;break;}
        }
        if(mp.find(now)!=mp.end()){
            cout<<"greska"<<endl;continue;
        }
        bool flag=false;
        fo(j,1,m){
            if(mp.find(bl[j])==mp.end())flag=true;
            ji[j]=mp.find(bl[j])->second;
        }
        if(flag){cout<<"greska"<<endl;continue;}
        fo(j,1,m){
            if(flag)break;
            fo(k,1,m){
                if(flag)break;
                bitset<N> tmp=bit[ji[j]]&bit[ji[k]];
                if(tmp.count()!=0&&bit[ji[j]][ji[k]]==0&&bit[ji[k]][ji[j]]==0)flag=true;
            }
        }
        if(flag){cout<<"greska"<<endl;continue;}
        cout<<"ok"<<endl;
        fo(j,1,m)bit[i]=bit[i]|bit[ji[j]];
        bit[i].set(i);mp.insert(make_pair(now,i));
    }
}

T4 kdgraph

这确实是个好题,不过我还是不会

我考场上是从小到大的判断的,并且我没有判断图的联通性,所以分很低

后来想了想,不能从小到大,因为不能判断图是否联通

所以我就从大到小了,这里要计算一个\(vis\)数组,表示我当前节点是属于那一个\(k-degree\)

这个几乎是整个题里最难的部分了

首先我们可以证明,删掉当前的点只会对度数比当前点大的点造成贡献(度数是指当前的度数,这个是随着删边不断变化的)

并且我们发现这个度数不会超过\(1e6\),所以我们可以直接桶排,直接从前向后遍历

这里有一些小小的细节,我们维护一个\(lin[i]\)数组,表示我最大的度数为\(i\)的点在数组中排名是多少

因为我操作前面度数小的点的时候,会删掉和度数大的点的连边,那么度数大的点就会向前走,直接交换到分界线的右侧就行了

最后删完之后,得到的剩下的度数就是当前点的\(vis\)

那么我们现在有了这个数组,直接从大到小枚举,不断想并查集中加入,当换\(k\)的时候就遍历前面的点,统计答案

AC_code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=1e6+5;
int n,m;
int to[N*2],nxt[N*2],head[N],rp=1;
int du[N];
ll ans1,ans2=-1e18,sn,sm,sd;
void add_edg(int x,int y){
    to[++rp]=y;
    nxt[rp]=head[x];
    head[x]=rp;
    du[y]++;
}
struct node{
    int id,vs;
    node(){}
    node(int x,int y){id=x;vs=y;}
}ok[N];
int vis[N],rak[N],sum[N],lin[N];
void get_vis(){
    fo(i,1,n)sum[du[i]]++;
    fo(i,1,n)sum[i]+=sum[i-1];
    fo(i,1,n)rak[i]=sum[du[i]]--;
    fo(i,1,n)ok[rak[i]]=node(i,du[i]);
    fo(i,1,n)if(ok[i].vs!=ok[i+1].vs)lin[ok[i].vs]=i;
    fo(x,1,n){
        for(int i=head[ok[x].id];i;i=nxt[i]){
            int y=to[i];
            if(ok[rak[y]].vs<=ok[x].vs)continue;
            ok[rak[y]].vs--;
            int sp=lin[ok[rak[y]].vs]+1,id=ok[sp].id;
            lin[ok[rak[y]].vs]++;
            swap(ok[rak[y]],ok[rak[id]]);
            swap(rak[y],rak[id]);
        }
    }
    fo(i,1,n)vis[ok[i].id]=ok[i].vs;//cout<<ok[i].id<<" "<<ok[i].vs<<endl;
}
int ns[N],ds[N],ms[N];
void get_now(){
    memset(sum,0,sizeof(sum));
    memset(rak,0,sizeof(rak));
    fo(i,1,n)sum[vis[i]]++;
    fo(i,1,n)sum[i]+=sum[i-1];
    fo(i,1,n)rak[i]=sum[vis[i]]--;
    fo(i,1,n)sum[rak[i]]=i;
    fo(i,1,n)ns[i]=1,ds[i]=du[i];
}
int fa[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void sol(){
    fo(i,1,n)fa[i]=i;
    fu(now,n,1){
        //cout<<"sb"<<endl;
        int x=sum[now],fx=find(x);
        for(int i=head[x];i;i=nxt[i]){
            int y=to[i];
            if(rak[y]<rak[x])continue;
            int fy=find(y);
            if(fx!=fy)fa[fy]=fx,ns[fx]+=ns[fy],ms[fx]+=ms[fy],ds[fx]+=ds[fy];
            ms[fx]++;
        }
        if(vis[x]!=vis[sum[now-1]]){
            fo(i,now,n){
                if(vis[sum[i]]!=vis[x])break;
                int fy=find(sum[i]);
                ll tmp=1ll*sm*ms[fy]-1ll*sn*ns[fy]+1ll*sd*(ds[fy]-(ms[fy]<<1));
                if(tmp>ans2)ans1=vis[x],ans2=tmp;
            }
        }
    }
}
signed main(){
    freopen("kdgraph.in","r",stdin);
    freopen("kdgraph.out","w",stdout);
    scanf("%d%d",&n,&m);
    scanf("%lld%lld%lld",&sm,&sn,&sd);
    fo(i,1,m){
        int x,y;scanf("%d%d",&x,&y);
        add_edg(x,y);add_edg(y,x);
    }
    get_vis();
    //fo(i,1,n)cout<<vis[i]<<" ";
    get_now();sol();
    printf("%lld %lld",ans1,ans2);
}
posted @ 2021-09-20 17:31  fengwu2005  阅读(44)  评论(0编辑  收藏  举报