2022/3/20

142 篇文章 1 订阅
142 篇文章 0 订阅

J - Welcome Party

模拟比赛的时候,做到这个题脑子就不转了,一直是另外两个队友在做这个题,比完赛后看题解知道思路后竟然一发就过了,,也没用到并查集,只是简单的bfs(bfs yyds);可以发现这m条关系会把人分成若干个组,有几个组答案就是几,这个直接用bfs做就行,要从1到n开始做,因为我们还要把每个组的最小值入队列,正序遍历正好满足这个条件了;弄完之后,每个组的最小值在队列了,然后每次输出队列的最小值(这个队列指的是优先队列),然后将和他一组的人入队列,再输出下一个最小值,知道队列为空;

(2条消息) J - Welcome Party(2019浙江省省赛)(bfs+优先队列)_Dream Flying Eagle的博客-CSDN博客

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,m,vis[1000006];
vector<ll>v[1000006];
priority_queue<ll,vector<ll>,greater<ll> >q;
void bfs(ll u){
    queue<ll>q1;
    q1.push(u);
    while(!q1.empty()){
        ll now=q1.front();q1.pop();
        if(vis[now]) continue;
        vis[now]=1;
        for(int i=0;i<v[now].size();i++){
            ll j=v[now][i];
            if(!vis[j]) q1.push(j);
        }
    }
}
int main(){
   // freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;i++) vis[i]=0,v[i].clear();
        for(int i=1;i<=m;i++){
            ll x,y;
            scanf("%lld%lld",&x,&y);
            v[x].push_back(y);
            v[y].push_back(x);
        }
        ll ans=0;
        for(int i=1;i<=n;i++)
            if(!vis[i]) bfs(i),ans++,q.push(i);
        printf("%lld\n",ans);
        for(int i=1;i<=n;i++) vis[i]=0;
        while(!q.empty()){
            ll u=q.top();q.pop();
            if(vis[u]) continue;
            vis[u]=1;
            if(u==1) printf("%lld",u);
            else printf(" %lld",u);
            for(int i=0;i<v[u].size();i++){
                ll j=v[u][i];
                if(!vis[j]) q.push(j);
            }
        }
        printf("\n");
    }
    return 0;
}

K - Strings in the Pocket 马拉车算法

通过这个题新学了个马拉车算法,可以求出最大回文串的长度;当s==t的话,用马拉车算法求出以s[i]为中心的回文串最大长度全部除以2加起来就是答案;若不想等的话,那就找到第一个和最后一个不相等的位置,看看反转后可不可以,不可以就是0,可以就继续向外扩展;

(2条消息) 2019年浙江省赛K题 Strings in the Pocket (Manachar)_ccdxc的博客-CSDN博客

马拉车算法,这个人讲的挺好(2条消息) Manacher算法(马拉车算法)_nowting_csdn的博客-CSDN博客_马拉车算法 

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll n,ans,len;
string s,t;
void manachar(){
    string str="$#";
    for(int i=0;i<len;i++){
        str+=s[i];str+="#";
    }
    ll m=str.size();
    vector<ll>p(m,0);
    ll id=0,mx=0;

    for(int i=1;i<m;i++){
        p[i]=mx>i?min(p[id*2-i],mx-i):1LL;
        while(str[i+p[i]]==str[i-p[i]]) p[i]++;
        if(i+p[i]>mx){
            mx=p[i]+i;
            id=i;
        }
        ans+=p[i]/2;//p[i]-1是原来字符串的长度,只考虑一边的话就是(p[i]-1+1)/2也就是p[i]/2了
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld",&n);
    while(n--){
        cin>>s>>t;
        len=s.size();
        ans=0;
        if(s==t) manachar();
        else{
            ll l=0,r=len-1;
            while(s[l]==t[l]&&l<len) l++;
            while(s[r]==t[r]&&r>=0) r--;
            string s1=s.substr(l,r-l+1);
            string t1=t.substr(l,r-l+1);
            reverse(s1.begin(),s1.end());
            if(s1==t1){
                ans=1;
                for(int i=1;i<min(l+1,len-r);i++){
                    if(s[l-i]==s[r+i]) ans++;
                    else break;
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

B - Element Swapping  数学推导

这题需要大胆的推公式,模拟比赛的时候看懂题意后就没敢往下做了,主要都在做J题,没有心思再做这个题;求出x,y和sum1(现在的x),sum2(现在的y)的关系,然后可以得出两个数的和与x,y,sum1,sum2有关系,之后再根据第一个式子可以得出能求出b的下标的式子;

(2条消息) 2019 浙江省赛 B-Element Swapping_yintama%QCT的博客-CSDN博客

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,x,y,a,b[100005];
map<ll,ll>mp;
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld%lld%lld",&n,&x,&y);
        ll sum1=0,sum2=0,ans=0;
        for(int i=1;i<=n;i++){
            scanf("%lld",&b[i]);
            mp[b[i]]++;
            sum1+=i*b[i];sum2+=i*b[i]*b[i];
        }
        if(x==sum1&&y==sum2){
            for(int i=1;i<=n;i++){
                ll num=mp[b[i]];
                if(num)
                ans+=num*(num-1)/2;
                mp[b[i]]=0;
            }
        }
        else if(x!=sum1&&y!=sum2&&(y-sum2)%(x-sum1)==0){
            ll num=(y-sum2)/(x-sum1);
            for(int i=1;i<=n;i++){
                ll a=num-b[i];
                if(b[i]!=a&&(x-sum1-(a-b[i])*i)%(b[i]-a)==0){
                    ll k=(x-sum1-(a-b[i])*i)/(b[i]-a);
                    if(k>=1&&k<=n&&b[k]==a) ans++;
                }
            }
            ans/=2;
        }
        printf("%lld\n",ans);
        for(int i=1;i<=n;i++) mp[b[i]]=0;
    }
    return 0;
}

D - Traveler

这题一开始看到的题解很蒙,没有看懂,又找了一份题解感觉像是瞎搞的,找到了一个规律,

ai=(a(i-2)+1)*2+1,从n开始像小的枚举,存到栈里;从1开始遍历,遍历的时候能向后退就后退,不行就乘以2再不行就乘以2加1,这样就能列出所有的数来;但我不知道原理是啥,只能说是只适用于这个题的伪规律吧,看起来像瞎搞。。。

(2条消息) ZOJ 4103 浙江省第16届大学生程序设计竞赛 D题 Traveler 构造_weixin_30681121的博客-CSDN博客

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,vis[100005];
vector<ll>v;
stack<ll>st;
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    vis[0]=1;
    while(t--){
        scanf("%lld",&n);
        v.clear();
        for(int i=1;i<=n;i++) vis[i]=0;
        while(n>1){
            st.push(n);
            if(n&1) n=(n-1)/2-1;
            else n=n/2-1;
        }
        ll now=1;
        while(1){
            v.push_back(now);
            vis[now]=1;
            if(!vis[now-1]) now--;
            else{
                if(st.empty()) break;
                else if(now*2==st.top()&&!vis[now*2]) now*=2,st.pop();
                else if(now*2+1==st.top()&&!vis[now*2+1]) now=now*2+1,st.pop();
                else{
                    if(!vis[now*2]) now*=2;
                    else if(!vis[now*2+1]) now=now*2+1;
                }

            }
        }
        for(int i=0;i<v.size();i++)
        printf("%lld%c",v[i],i==v.size()-1?'\n':' ');
    }
    return 0;
}

C - Array in the Pocket

尽可能地让小数排在前面,如果碰到b[i]==a[i]了,那就尽量去后面找b[i]!=a[i]的位置填上,实在不行再去前面找,这个题实现方式没想到,,有些许复杂

(2条消息) C - Array in the Pocket (ZOJ - 4102)_hrbust_wgq的博客-CSDN博客

#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,a[100005],ans[100005],cnt[100005];
vector<ll>pos[100005],res[100005];
set<ll>s;
int main(){
   //freopen("in.txt","r",stdin);
    scanf("%lld",&t);
    while(t--){
        scanf("%lld",&n);
        s.clear();
        bool flag=0;
        for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]),cnt[i]=0,pos[i].clear(),res[i].clear(),ans[i]=0;
        for(int i=1;i<=n;i++){
            cnt[a[i]]++;
            if(cnt[a[i]]>=n/2+1) flag=1;
            s.insert(a[i]);
        }
        if(flag){
            printf("Impossible\n");continue;
        }
        for(int i=1;i<=n;i++){
            ll val=*s.begin();
        if(s.size()==1&&val==a[i]){//去试后面的数可不可以
            for(int j=i+1;j<=n;j++)
            if(val!=a[j]){
                ans[j]=val;
                cnt[val]--;
            }
            vector<ll>poss,tmp;
            for(int j=i;j<=n;j++){//看看后面有多少个不能填的数
                if(a[j]==val) poss.push_back(j);
            }
            for(int j=i-1;j>=1;j--){//看看前面有多少个能填(换)的数
                if(cnt[val]<=0) break;
                if(ans[j]!=val&&a[j]!=val){
                    tmp.push_back(ans[j]);
                    ans[j]=val;
                    cnt[val]--;
                }
            }
            ll len=poss.size();
            for(int j=0;j<len;j++){//将val与之前的ans[j]换位置
                ans[poss[j]]=tmp[j];
            }
            if(cnt[val]<=0) break;
        }
        else{
            auto it=s.begin();
            val=*it;
            if(val==a[i]) it++;//不行就去试下一个
            val=*it;
            ans[i]=val;
            cnt[val]--;
            if(cnt[val]<=0) s.erase(val);
        }
        }
        //将每个a[i]确定的数都放进一个vector里,方便后面排序(因为要输出字典序最小)
        for(int i=1;i<=n;i++){
            pos[a[i]].push_back(i);
            res[a[i]].push_back(ans[i]);
        }
        for(int i=1;i<=n;i++){
            if(pos[i].size()<=0) continue;
            sort(pos[i].begin(),pos[i].end());
            sort(res[i].begin(),res[i].end());
            for(int j=0;j<pos[i].size();j++)
            ans[pos[i][j]]=res[i][j];
        }
        for(int i=1;i<=n;i++){
            printf("%lld%c",ans[i],i==n?'\n':' ');
        }
    }
    return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值