BOJ 2014新生暑假个人排位赛07 整合

本文深入探讨了算法与数据结构的核心概念,包括排序算法、动态规划、哈希算法等,旨在帮助读者理解和掌握这些基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. 暑假作业题


大模拟, 字符串读入时要注意前导0


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <climits>
 
#define MAXN 100005
#define eps 1e-5
#define MOD 1000000009
 
#define test
 
#define For(i,m,n) for(int i=(m);i<(n);i++)
#define vecfor(iter,a) for(vector<int>::iterator iter=a.begin();iter!=a.end();iter++)
#define rep(i,m,n) for(int i=(m);i<=(n);i++)
#define LL long long
 
/*author birdstorm*/
using namespace std;
const double pi=acos(-1.0);
 
template<class T>
inline bool read(T &n){
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
 
template <class T>
inline void write(T n) {
    if(n < 0) {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n) {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
 
int main()
{
    int t;
    LL a;
    char c[20];
    read(t);
    while(t--){
        scanf("%s",c);
        int cnt=strlen(c);
        bool flag1w=false, flag1e=false;
        bool flagb=false, flagq=false, f3=true;
        if(cnt==1&&c[0]=='0') printf("0");
        for(int i=0; i<cnt; i++){
            int p=cnt-i-1;
            bool flag=false;
            if(c[i]-'0'){
                printf("%d",c[i]-'0');
                flag=true;
                if(p>=4&&p<8) flag1w=true;
                if(p>=13&&p<16) flag1w=true;
                if(p>=8) flag1e=true;
            }
            else{
                if(c[i+1]-'0'&&p>4&&p<8&&flag1w) printf("0");
                else if(c[i+1]-'0'&&p>13&&p<16&&flag1w) printf("0");
                else if(c[i+1]-'0'&&(p==1||p==5||p==9||p==13)) printf("0");
                else if(c[i+1]-'0'&&(p==2||p==6||p==10||p==14)) printf("0");
                else if(c[i+1]-'0'&&(p==3||p==7||p==11||p==15)) printf("0");
                //continue;
            }
            if(p==13) flag1w=false;
            if(!flag){
                if(flag1w&&p==4) printf("W"),flag1w=false;
                if(flag1e&&p==12) printf("W"),flag1w=false;
                if(flag1e&&p==8) printf("E"),flag1e=false;
                continue;
            }
            if(p==1||p==5||p==9||p==13) printf("S");
            if(p==2||p==6||p==10||p==14) printf("B");
            if(p==3||p==7||p==11||p==15) printf("Q");
            if(p==4||p==12) printf("W");
            if(p==8) printf("E");
        }
        puts("");
    }
    return 0;
}



B. 最长数链


暴力使用dfs搜索 

正确的姿势是发现数链中的数只可能是2和3的倍数, 大大降低复杂度, 可以log(n)求出

这个姿势有点慢了= =



#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <climits>
 
#define MAXN 100005
#define eps 1e-5
#define MOD 1000000009
 
#define test
 
#define For(i,m,n) for(int i=(m);i<(n);i++)
#define vecfor(iter,a) for(vector<int>::iterator iter=a.begin();iter!=a.end();iter++)
#define rep(i,m,n) for(int i=(m);i<=(n);i++)
#define LL long long
 
/*author birdstorm*/
using namespace std;
const double pi=acos(-1.0);
 
template<class T>
inline bool read(T &n){
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
 
template <class T>
inline void write(T n) {
    if(n < 0) {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n) {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
 
int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43};
int sta[MAXN],stac[MAXN];
int dfs(int g,int pos,int cnt)
{
    int ans=-1;
    if(g==1) return cnt;
    else{
        For(i,pos,13){
            if(g%prime[i]==0){
                int len=dfs(g/prime[i],i,cnt+1);
                //if(len==-1) break;
                if(ans<=len){
                    ans=len;
                    sta[cnt+1]=prime[i];
                }
            }
        }
    }
    return ans;
}
int ans;
int main()
{
    int a;
    while(read(a)){
        ans=0;
        int t;
        memset(sta,0,sizeof sta);
 
        for(int i=a/2+1;i<=a;i++){
            int len=dfs(i,0,0);
            if(len>=ans){
                ans=len;
                For(j,0,ans+1) stac[j]=sta[j];
                t=i;
            }
        }
        //ans=dfs(t,0,0);
        //For(j,0,ans+1) stac[j]=sta[j];
        int g=1;
        printf("1");
        for(int i=ans;i>=1;i--){
            printf(" %d",g*stac[i]);
            g*=stac[i];
            if(g==t) break;
        }
        puts("");
    }
    return 0;
}



C. 三角形的传说


可以证明只有三种可能解, 判断即可



#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <climits>
 
#define MAXN 100005
#define eps 1e-5
#define MOD 1000000009
 
#define test
 
#define For(i,m,n) for(int i=(m);i<(n);i++)
#define vecfor(iter,a) for(vector<int>::iterator iter=a.begin();iter!=a.end();iter++)
#define rep(i,m,n) for(int i=(m);i<=(n);i++)
#define LL long long
 
/*author birdstorm*/
using namespace std;
const double pi=acos(-1.0);
 
template<class T>
inline bool read(T &n){
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
 
template <class T>
inline void write(T n) {
    if(n < 0) {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n) {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
 
 
int main()
{
    int t, cs=1;
    int m, q;
    scanf("%d",&t);
    while(t--){
        read(m),read(q);
        printf("Case %d: ",cs++);
        int ans=10000000;
        if(m%2==0){
            if(m>=q*2){
                ans=2*q+2*m;
            }
            else ans=2*q+m;
        }
        else{
            if(2*q>m){
                ans=2*q+m;
            }
            else ans=2*q+2*m;
        }
        if(q<=1) ans=3*m+2*q;
        printf("%d\n",ans);
    }
    return 0;
 
}



D. 帮帮小叮当



dp/图论

dp的正确性: 由于是从确定状态转移至不确定状态, 所以dp的结果正确.

图论可采用SPFA, 速度也不慢.

可是使用dij+堆优化的话似乎不能在时限内通过, 原因不明



#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <climits>
 
#define MAXN 100005
#define eps 1e-5
#define MOD 1000000007
#define INF 1000000007
 
#define test
 
#define For(i,m,n) for(int i=(m);i<(n);i++)
#define vecfor(iter,a) for(vector<int>::iterator iter=a.begin();iter!=a.end();iter++)
#define rep(i,m,n) for(int i=(m);i<=(n);i++)
#define LL long long
 
/*author birdstorm*/
using namespace std;
const double pi=acos(-1.0);
 
template<class T>
inline bool read(T &n){
    T x = 0, tmp = 1; char c = getchar();
    while((c < '0' || c > '9') && c != '-' && c != EOF) c = getchar();
    if(c == EOF) return false;
    if(c == '-') c = getchar(), tmp = -1;
    while(c >= '0' && c <= '9') x *= 10, x += (c - '0'),c = getchar();
    n = x*tmp;
    return true;
}
 
template <class T>
inline void write(T n) {
    if(n < 0) {
        putchar('-');
        n = -n;
    }
    int len = 0,data[20];
    while(n) {
        data[len++] = n%10;
        n /= 10;
    }
    if(!len) data[len++] = 0;
    while(len--) putchar(data[len]+48);
}
 
int dp[MAXN], a[MAXN];
int main()
{
    int n, m;
    while(read(n)&&read(m),n||m){
        For(i,0,n) read(a[i]);
        int ans=INF;
        dp[0]=a[0]-1;
        For(i,1,n) dp[i]=min(dp[i-1]+1,i+a[i]-1);
        for(int i=n-2;i>=0;i--) dp[i]=min(dp[i],dp[i+1]+1);
        For(i,0,n) ans=min(ans,dp[i]+n-i+m-a[i]-1);
        printf("%d\n",ans);
    }
    return 0;
}



E. hiyot的神题



线段树维护区间gcd, 然后使用容斥原理计算答案.

考虑到1000以内的数分解素数后最多只有五个, 也可以暴力手算容斥.

比如:

LL solve(LL a, LL m)
{
    int sz=g[a].size();
    LL ret=0;
    if(sz==1) ret=m-m/g[a][0];
    else if(sz==2) ret=m-m/g[a][0]-m/g[a][1]+m/(g[a][0]*g[a][1]);
    else if(sz==3){
        LL a1=g[a][0], a2=g[a][1], a3=g[a][2];
        ret=m-m/a1-m/a2-m/a3+m/(a1*a2)+m/(a1*a3)+m/(a2*a3)-m/(a1*a2*a3);
    }
    else if(sz==4){
        LL a1=g[a][0], a2=g[a][1], a3=g[a][2], a4=g[a][3];
        ret=m-m/a1-m/a2-m/a3-m/a4+m/(a1*a2)+m/(a1*a3)+m/(a1*a4)+m/(a2*a3)+m/(a2*a4)+m/(a3*a4)-m/(a1*a2*a3)-m/(a1*a2*a4)-m/(a1*a3*a4)-m/(a2*a3*a4)+m/(a1*a2*a3*a4);
    }
    else if(sz==5){
        LL a1=g[a][0], a2=g[a][1], a3=g[a][2], a4=g[a][3], a5=g[a][4];
        ret=m-m/a1-m/a2-m/a3-m/a4-m/a5+m/(a1*a2)+m/(a1*a3)+m/(a1*a4)+m/(a1*a5)+m/(a2*a3)+m/(a2*a4)+m/(a2*a5)+m/(a3*a4)+m/(a3*a5)+m/(a4*a5)-m/(a1*a2*a3)-m/(a1*a2*a4)-m/(a1*a2*a5)-m/(a1*a3*a4)-m/(a1*a3*a5)-m/(a1*a4*a5)-m/(a2*a3*a4)-m/(a2*a3*a5)-m/(a2*a4*a5)-m/(a3*a4*a5)+m/(a1*a2*a3*a4)+m/(a1*a2*a3*a5)+m/(a1*a2*a4*a5)+m/(a1*a3*a4*a5)+m/(a2*a3*a4*a5)-m/(a1*a2*a3*a4*a5);
    }
    return ret-1;
}


这里推荐的是比较优美的dfs姿势



#include <cstdio>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <vector>
#include <algorithm>
#define MAXN 10005
#define For(i,m,n) for(int i=(m);i<(n);i++)
#define LL long long
    
using namespace std;
LL prime[]={2,3,5,7,11,13,17,19,23,29,31};
struct node{
    int left, right;
    LL gcd;
}arr[MAXN<<4];
    
LL num[MAXN], c;
LL gcd(LL a, LL b)
{
    return b==0?a:gcd(b,a%b);
}
void build(int idx, int l, int r){
    arr[idx].left = l, arr[idx].right = r;
    arr[idx].gcd = 0;
    if(l == r){
        arr[idx].gcd = num[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(idx << 1, l, mid);
    build(idx << 1 | 1, mid + 1, r);
    arr[idx].gcd = gcd(arr[idx << 1].gcd , arr[idx << 1 | 1].gcd);
}
LL ans;
bool query(int idx, int l, int r){
    if(arr[idx].right < l||arr[idx].left > r) return false;
    if(arr[idx].left >= l&&arr[idx].right <= r){
        ans=gcd(ans,arr[idx].gcd);
        return true;
    }
    query(idx << 1, l, r);
    query(idx << 1 | 1, l, r);
    return true;
}
    
void update(int idx, int val, int pos)
{
    int l = arr[idx].left, r = arr[idx].right;
    if(l == r){
        arr[idx].gcd=val;
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(idx << 1, val, pos);
    else update(idx << 1 | 1, val, pos);
    arr[idx].gcd = gcd(arr[idx<<1].gcd, arr[idx<<1|1].gcd);
}
vector<LL> g[1111], v;
void init()
{
    for(LL i=2; i<=1000; ++i){
        g[i].clear();
        LL tmp=i;
        For(j,0,11){
            if(tmp%prime[j]==0){
                while(tmp%prime[j]==0) tmp/=prime[j];
                g[i].push_back(prime[j]);
            }
        }
        if(tmp!=1) g[i].push_back(tmp);
    }
}
    
LL dfs(int pos, int sz, LL a, LL m)
{
    LL ret=0;
    For(i,pos,sz){
        ret+=m/g[a][i]-dfs(i+1,sz,a,m/g[a][i]);
    }
    return ret;
}
    
int main()
{
    int t, n, q, l, r;
    LL g1, m;
    init();
    while(~scanf("%d",&n)){
        scanf("%lld%d",&m,&q);
        For(i,1,n+1) scanf("%lld",&num[i]);
        build(1,1,n);
        int o;
        while(q--){
            scanf("%d%d",&o,&l);
            if(o==1){
                scanf("%d",&r);
                ans=num[l];
                query(1,l,r);
                if(ans==1) printf("-1\n");
                else{
                    int sz=g[ans].size();
                    LL ret=m-1-dfs(0,sz,ans,m);
                    printf("%lld\n",ret);
                }
            }
            else{
                scanf("%lld",&g1); num[l]=g1;
                update(1,g1,l);
            }
        }
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值