2017-2018 ACM-ICPC, NEERC, Northern Subregional Contest训练赛

两个紫名大佬带我躺。。。

题目

这里只写我看了题意的题:

Problem C. Consonant Fencity:

英语渣表示看不懂题目,题意是这样给一个全小写字符串,期中有A和B类字符,求B类字符相邻一个为大写一个为小写的个数最多的串,也就是自己构造一些字符全部替换成大写,一些字符替换成全部为小写。

1、那么只有19个字符,枚举每个字符是否为大写还是小2^19

2、然后把两个小写字母相邻的种数记录下来,这样就不用每次枚举一整个串(关键),每次就在这2^19种找19*19种可能取最大值

复杂度为1e8

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
const double eps=1e-6;
char s1[maxn];
int num[200];
int dp[205][205];
int U[200];
vector<int>q1;
int main(){
    int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
    //freopen("in.txt","r",stdin);
    freopen("consonant.in","r",stdin);
    freopen("consonant.out","w",stdout);
    scanf("%s",&s1);
    int len1,len2,len3;
    len1=strlen(s1);
    //num[65]
    num[65+32]=1;num[69+32]=1;num[73+32]=1;
    num[89+32]=1;num[85+32]=1;num[79+32]=1;
    num[87+32]=1;
    for(i=97;i<=122;i++){
        if(num[i]==0){
        q1.push_back(i);
        }
    }
    for(i=1;i<len1;i++){
        if(num[s1[i-1]]+num[s1[i]]==0){
            dp[s1[i-1]][s1[i]]++;
        }
    }
    /*for(i=1;i<=200;i++)
        for(j=1;j<=200;j++){
            if(dp[i][j]){
                char a,b;
                a=i;b=j;
            }
        }*/
    int S=(1<<19);
    int res,max1;
    max1=0;
    int num1;
    for(i=0;i<S;i++){
        num1=0;
        for(j=0;j<19;j++)
            for(k=0;k<19;k++){
                t1=(i>>j)&1;
                t2=(i>>k)&1;
                if(t1+t2==1){
                num1+=dp[q1[j]][q1[k]];
                }
            }
            if(num1>max1){
            max1=num1;
            res=i;
            }
    }
    for(i=0;i<19;i++){
        if((res>>i)&1){
            U[q1[i]]=1;
        }
    }
    for(i=0;i<len1;i++){
        if(U[s1[i]]==1)
        s1[i]-=32;
    }
    cout <<s1<<endl;
    return 0;
}

K. Kotlin Island

给一个r*c的网格土地,初始为一块大干旱地,每次选择一行或一列全部浇水,当相邻均为湿润的时候,那么可以得到,

可以得知对于浇水的顺序来说是无影响的,那么当只考虑c时,每次多添一个c,结果总数+1,对于一个固定的c,每个r可以把+c,也就是当考虑c与r时,可以得知对于画r和c的总共土地数量=(r+1)*(c+1),而r与c应该在为偶数的时候才画,想要画3个r,则需要3*2+1的总长才能画上,那么结果就是对一个结果k,对其进行因子枚举,然后判断满足r与c的长度就够,够的话直接构造。这里对于可以把全部作为r>c的情况进行考虑,因为if(c>r)swap(r,c),mark=1,那么下次转换过来的时候把所有标记同时转换均可。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
const double eps=1e-6;
int q1[maxn];
int q2[maxn];
int dp[105][105];
int num[2][105];
int main(){
    int i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
    //freopen("in.txt","r",stdin);
    freopen("kotlin.in","r",stdin);
    freopen("kotlin.out","w",stdout);
    int g1,g2,g3;
    int n,m;
    int r1,c1;
    cin >> n>> m >>k;
    t1=n*m;
    if(t1%2==1)t1++;
    t1/=2;
    if(k>t1){
    cout <<"Impossible"<< endl;
    return 0;
    }
    int mark=0;
    int C1,R1;
    if(n<m){
    swap(n,m);mark=1;
    }
    C1=R1=0;
    if(n>=k*2-1){
        k--;
        R1=k;C1=0;
        if(mark){
        swap(n,m);
        swap(R1,C1);
        }
        for(i=1;i<=n;i++){
            for(j=1;j<=m;j++)
                if((i%2==0&&i<=2*R1)||(j%2==0&&j<=2*C1))cout <<"#";
                else cout <<".";
                cout << endl;
        }
        return 0;
    }else{
        for(i=2;i*i<=k;i++){
            if(k%i==0){
                j=k/i;
                r1=j-1;
                c1=i-1;
                //cout <<i <<"   "<<j<< endl;
                if(n>=r1*2+1&&m>=c1*2+1){
                    C1=c1;R1=r1;
                    //cout << mark <<"   " <<R1<<"    "<<C1<< endl;
                    //return 0;
                   break;
                }
            }
        }
        if(C1!=0||R1!=0){
            if(mark){
            swap(R1,C1);
            swap(n,m);
            }
            for(i=1;i<=n;i++){
                for(j=1;j<=m;j++)
                    if((i%2==0&&i<=2*R1)||(j%2==0&&j<=2*C1))
                    cout <<"#";
                    else
                    cout <<".";
            cout << endl;
            }
        }
    }
    if(C1==0&&R1==0)
    cout <<"Impossible"<< endl;

    return 0;
}

L. Little Difference:

给一个数字n(1e18),找出值差不超过1的数进行相乘得到n,问有多少种方法,输出方案。

比如12:可以由3*4,2*2*3。得到显然可以得到一个思路。通过开pow(n,1/i);可以得到n这个数字分成1/i份的时候的值大小。

做法一:

一个数字最多可以由63个数相乘得到,那么这个个数x要么是pow(n,1/i)*i直接得到,要么是其与其+1,也就是(a)^c+(b)^d得到。

那么我们对于这个c与d的个数二分即可得到是否可以构成这个值。

这里存在一个问题pow(n,1/i)吃精度严重,尤其是质数的时候,这里可以考虑质数特判输出(骗过去的,考虑c++14。

#include<stdio.h>
#include<math.h>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=1e6+7;
const double eps=1e-8;
typedef unsigned long long ll;

ll pow1(ll x,ll y){
    ll a=x;
    for(ll i=2;i<=y;i++){
        a*=x;
    }
    return a;
}
vector<ll>R[100];
int main(){
    ll i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
    //freopen("in.txt","r",stdin);
    freopen("little.in","r",stdin);
    freopen("little.out","w",stdout);
    ll g1,g2,g3,g4,g5,g6;
    cin >> g1;
    if(g1==1){
        cout <<"-1"<< endl;return 0;
    };
    g2=g1;
    while(g2%2==0)g2/=2LL;
    if(g2==1){
        cout <<"-1"<< endl;return 0;
    }
    double k1,k2,k3;
    g3=0;
    ll left1,right1,mid1,key1;
    ll res1,res2;
    int T=0;
    T++;
    R[T].push_back(g1);
    for(i=2;i<=60;i++){
        k1=pow(g1,1.0/i)+eps;
        if(g3==k1)continue;
        g3=k1;
        if(pow1(g3,i)==g1){
            T++;
            for(j=1;j<=i;j++)
            R[T].push_back(g3);
        }
        g4=g3+1;
        left1=1;right1=i-1;
        res1=0;
        while(right1>=left1){
            mid1=(left1+right1)/2;
            key1=pow1(g3,mid1)*pow1(g4,i-mid1);
            if(key1>=g1){
            left1=mid1+1;
            if(key1==g1){
            res1=mid1;
            break;
            }
            }else{
            right1=mid1-1;
            }
        }
        if(res1==0)continue;
            T++;
            for(j=1;j<=res1;j++)
            R[T].push_back(g3);
            for(j=res1+1;j<=i;j++)
            R[T].push_back(g4);
    }
    cout <<T<< endl;
    for(i=1;i<=T;i++){
        cout << R[i].size();
        for(j=0;j<R[i].size();j++)
        cout <<" "<<R[i][j];
        cout << endl;
    }
    return 0;
}

做法二:

还可以考虑枚举值或者二分这个值。枚举的时候把2个数相乘的结果特判,而从i*i*i<=n的作为输出条件,就把复杂度降到n^(1/3)了。

#include<stdio.h>
#include<math.h>
#include<iostream>
#include<vector>
using namespace std;
const int maxn=1e6+7;
const double eps=1e-8;
typedef unsigned long long ll;
vector<ll>R[100];
int main(){
    ll i,j,k,f1,f2,f3,f4,t1,t2,t3,t4;
    //freopen("in.txt","r",stdin);
    freopen("little.in","r",stdin);
    freopen("little.out","w",stdout);
    ll g1,g2,g3,g4,g5,g6;
    cin >> g1;
    if(g1==1){
        cout <<"-1"<< endl;return 0;
    };
    g2=g1;
    while(g2%2==0)g2/=2LL;
    if(g2==1){
        cout <<"-1"<< endl;return 0;
    }
    double k1,k2,k3;
    g3=0;
    ll left1,right1,mid1,key1;
    ll res1,res2;

    int T=0;
    T++;
    R[T].push_back(g1);
    g2=sqrt(g1);
    if(g2*g2==g1){
    T++;
    R[T].push_back(g2);
    R[T].push_back(g2);
    }else if(g2*(g2+1)==g1){
    T++;
    R[T].push_back(g2);
    R[T].push_back(g2+1);
    }
    for(i=2;i*i*i<=g1;i++){
        if(g1%i==0){ //可以整除这个数字
            t1=t2=0;
            g3=g1;
            while(g3>=i&&g3%i==0){
            t1++;g3/=i;
            }
            if(g3==1){
            T++;
            for(j=1;j<=t1;j++)
            R[T].push_back(i);
            continue;
            }
            while(g3>=(i+1)&&g3%(i+1)==0){
            t2++;g3/=(i+1);
            }
            if(g3==1){
            T++;
            for(j=1;j<=t1;j++)
            R[T].push_back(i);
            for(j=1;j<=t2;j++)
            R[T].push_back(i+1);
            }
        }
    }
    cout <<T<< endl;
        for(i=1;i<=T;i++){
        cout << R[i].size();
        for(j=0;j<R[i].size();j++)
        cout <<" "<<R[i][j];
        cout << endl;
    }
    return 0;
}

E. Equal Numbers

要求每次可以给一个数乘一个任意的数字,使得这次操作后这组序列不用数字的个数最少。
可以考虑浪费一次转换的次数(直接转换成某个数的因子的方法),那么以后每次转换都可以直接转换为这个无穷大的数字

这个结论显然是错误的,因为当出现一个数字在一开始直接可以转换成为某一个数的因子的时候其的个数直接-1。

那么可以贪心和第一种策略进行比较,这条贪心的线只有在把全部为因子且出现次数较小排序,当其没有第一种优的时候取第一种即可。

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int maxn=1e6+7;
const double eps=1e-8;
struct ttt{
    int key,num;
    int i,is;
};
int id[maxn],q2[maxn],num[maxn];
ttt q1[maxn];
ttt q3[maxn];
bool vis[maxn];
int cmp1(ttt x,ttt y){
    if(x.num!=y.num)
    return x.num<y.num;
    return x.is>y.is;
}
int cmp2(ttt x,ttt y){
    if(x.is!=y.is)
    return x.is>y.is;
    else
    return x.num<y.num;
}
int main(){
    int i,j,k,f1,f2,f3,f4,f5,t1,t2,t3,t4,t5,n,m;
    //freopen("in.txt","r",stdin);
    freopen("equal.in","r",stdin);
    freopen("equal.out","w",stdout);
    scanf("%d",&n);
    int cnt=0;
    int K;
    K=0;
    for(i=1;i<=n;i++){
        scanf("%d",&t1);
        for(j=1;j*j<=t1;j++){
                if(t1%j==0){
                    num[t1/j]++;
                    if(t1/j==j)continue;
                    num[j]++;
                }
        }
        if(vis[t1]==0){
        K++;
        cnt++;
        q1[cnt].key=t1;
        id[q1[cnt].key]=cnt;
        q1[id[t1]].num=1;
        vis[t1]=1;
        }else{
        q1[id[t1]].num++;
        }
    }
    for(i=1;i<=cnt;i++){
        if(num[q1[i].key]>q1[i].num){
            q1[i].is=1;
        }
    }
    for(i=1;i<=cnt;i++)
    q3[i]=q1[i];
    sort(q1+1,q1+1+cnt,cmp1);
    sort(q3+1,q3+1+cnt,cmp2);
    int K1,K2;
    K1=K2=K;
    printf("%d",K);
    int mark=0;
    int tot1,tot2;
    tot1=tot2=1;
    for(i=1;i<=n;i++){
        q1[tot1].num--;q3[tot2].num--;
        if(q1[tot1].num==0){
        tot1++;
        if(mark==0)K1++;
        mark=1;
        K1--;
        }
        if(q3[tot2].num==0){
        if(q3[tot2].is==1)K2--;
        tot2++;
        }
        if(i==n)
        printf(" 1\n");
        else
        printf(" %d",min(K1,K2));
    }
    return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值