2018ICPC焦作赛区网络预赛

传送门:https://www.jisuanke.com/contest/1558?view=challenges

A. Magic Mirror

签到模拟(通过率: 98.74 %,通过人数: 1650)

思路:把输入的字符串转成小写串,然后和”jessie”进行比较,如果相等就输出”Good guy!”,不然就输出另一个

// https://nanti.jisuanke.com/t/31710
#include<stdio.h>
#include<string.h>
char str[]="jessie";
char s[30];
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int t;scanf("%d",&t);
    while(t--){
        scanf("%s",s);
        for(char*p=s;*p;p++)
            *p|=32;
        if(strcmp(s,str)==0)
            puts("Good guy!");
        else
            puts("Dare you say that again?");
    }
    return 0;
}

~ B. Mathematical Curse

dp(通过率: 73.49 %,通过人数: 585)

思路:dp[i][j]代表用了前i个数字和前j个运算符所能达到的极值,+-只能从最大值转移到最大值,最小值转移到最小值,但是*/有可能有数是负数,所以要考虑最大值/最小值之间的相互转移.最后输出dp[n][m]的最大值.

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int maxn=1005,MAX=1,MIN=0;
ll max[maxn][6],min[maxn][6];
char s[7];int a[maxn];
void sel(int mode,ll&a,ll b){
    if(mode&&b>a)a=b;
    if(!mode&&b<a)a=b;
}
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int t;scanf("%d",&t);
    while(t--){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        scanf("%s",s+1);
        for(int i=0;i<maxn;i++)
            for(int j=0;j<6;j++)
                max[i][j]=-0x3f3f3f3f3f3f3f3f,
                min[i][j]=0x3f3f3f3f3f3f3f3f;
        max[0][0]=min[0][0]=k;
        for(int i=1;i<=n;i++){
            max[i][0]=min[i][0]=max[i-1][0];
            for(int j=1;j<=m&&j<=i;j++){
                switch(s[j]){
                    case '+':
                        sel(MAX,max[i][j],max[i-1][j]);
                        sel(MAX,max[i][j],max[i-1][j-1]+a[i]);
                        sel(MIN,min[i][j],min[i-1][j]);
                        sel(MIN,min[i][j],min[i-1][j-1]+a[i]);
                        break;
                    case '-':
                        sel(MAX,max[i][j],max[i-1][j]);
                        sel(MAX,max[i][j],max[i-1][j-1]-a[i]);
                        sel(MIN,min[i][j],min[i-1][j]);
                        sel(MIN,min[i][j],min[i-1][j-1]-a[i]);
                        break;
                    case '*':
                        sel(MAX,max[i][j],max[i-1][j]);
                        sel(MAX,max[i][j],max[i-1][j-1]*a[i]);
                        sel(MAX,max[i][j],min[i-1][j-1]*a[i]);
                        sel(MIN,min[i][j],min[i-1][j]);
                        sel(MIN,min[i][j],min[i-1][j-1]*a[i]);
                        sel(MIN,min[i][j],max[i-1][j-1]*a[i]);
                        break;
                    case '/':
                        sel(MAX,max[i][j],max[i-1][j]);
                        sel(MAX,max[i][j],max[i-1][j-1]/a[i]);
                        sel(MAX,max[i][j],min[i-1][j-1]/a[i]);
                        sel(MIN,min[i][j],min[i-1][j]);
                        sel(MIN,min[i][j],min[i-1][j-1]/a[i]);
                        sel(MIN,min[i][j],max[i-1][j-1]/a[i]);
                        break;
                }
            }
        }
        printf("%lld\n",max[n][m]);
    }
    return 0;
}

G. Give Candies

数论(通过率: 80.62 %,通过人数: 1202)

思路:首先需要求出来有N颗糖的发糖方案,是2^N(随便列几项找到的规律)
其次需要求出2^N%(1e9+7),利用费马小定理,直接将N%(1e+6)之后快速幂即可

// https://nanti.jisuanke.com/t/31716
#include<stdio.h>
typedef long long ll;
const int mod=1e9+7;
ll pow(ll x,ll y){
    ll ret=1;y%=mod;
    while(y){
        if(y&1)ret=ret*x%mod;
        x=x*x%mod;y/=2;
    }
    return ret;
}
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int t;scanf("%d%*c",&t);
    while(t--){
        ll y=0;char c;
        while((c=getchar())!='\n'&&c!=EOF)
            y=(y*10+c-'0')%(mod-1);
        printf("%lld\n",pow(2,y-1+mod));
    }
    return 0;
}

I. Save the Room

签到模拟(通过率: 98.37 %,通过人数: 1631)

思路:只要有一个偶数,2就可以在那个方向上填充满,所以当全是奇数的时候就不能全部填充满了

// https://nanti.jisuanke.com/t/31718
#include<stdio.h>
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int a,b,c;
    while(~scanf("%d%d%d",&a,&b,&c))
        puts((a%2)*(b%2)*(c%2)?"No":"Yes");
    return 0;
}

~ J. Participate in E-sports

大数求根(通过率: 51.65 %,通过人数: 298)

思路:只要判断n和n*(n-1)/2是不是完全平方数就可以了,主要是怎么开根的问题

// https://nanti.jisuanke.com/t/31719
import java.math.BigInteger;
public class Main{
    public static BigInteger bigSqrt(String s){
        BigInteger remain=BigInteger.ZERO;
        BigInteger odd=BigInteger.ZERO;
        BigInteger ans=BigInteger.ZERO;
        int group=0,k=0;
        if(s.length()%2==1){
            group=s.charAt(0)-'0';
            k--;
        }
        else{
            group=(s.charAt(0)-'0')*10+s.charAt(1)-'0';
        }
        for(int j=0;j<(s.length()+1)/2;j++){
            if(j!=0)
                group=(s.charAt(j*2+k)-'0')*10+s.charAt(j*2+k+1)-'0';
            odd=BigInteger.valueOf(20).multiply(ans).add(BigInteger.ONE);
            remain=BigInteger.valueOf(100).multiply(remain).add(BigInteger.valueOf(group));
            int count=0;
            while(remain.compareTo(odd)>=0){
                count++;
                remain=remain.subtract(odd);
                odd=odd.add(BigInteger.valueOf(2));
            }
            ans=ans.multiply(BigInteger.TEN).add(BigInteger.valueOf(count));
        }
        return ans;
        /*

            remind=0;
            odd=0;
            ans=0;
            group=0;
            k=0;
            if(s.length()%2==1)
                group=s[0]-'0',k--;
            else
                group=s[0]*10+s[1]-'0'*11;
            for(int j=0;j<(s.length()+1)/2;j++){
                if(j)
                    group=s[j*2+k]*10+s[j*2+k+1]-'0'*11;
                odd=20*ans+1;
                remind=100*remind+group;
                int count=0;
                while(remain>=odd){
                    count++;
                    remain-=odd;
                    odd+=2;
                }
                ans=ans*10+count;
            }
            return ans;

        */
    }
    public static void main(String[] args){
        try{
            java.io.FileInputStream fis=new java.io.FileInputStream("E:/ACM/SRC/1.txt");
            System.setIn(fis);
        }catch(Exception e){}
        try{
            java.io.FileInputStream fis=new java.io.FileInputStream("E:/ACM/SRC/1.txt");
            System.setIn(fis);
        }catch(Exception e){}
        java.util.Scanner cin=new java.util.Scanner(System.in);
        int t=cin.nextInt();
        for(int i=0;i<t;i++){
            BigInteger num=cin.nextBigInteger();
            BigInteger ans=num.multiply(num.subtract(BigInteger.ONE)).divide(BigInteger.valueOf(2));
            String sans=ans.toString();
            String snum=num.toString();
            BigInteger a1=bigSqrt(snum);
            BigInteger a2=bigSqrt(sans);
            int t1=a1.multiply(a1).compareTo(num)==0?2:0;
            int t2=a2.multiply(a2).compareTo(ans)==0?1:0;
            /*

                cin>>num;
                ans=num*(num-1)/2;
                a1=sqrt(num);
                a2=sqrt(ans);
                t1=(a1*a1==num)*2;
                t2=(a2*a2==num)*1;

            */
            String[] ans_str={"League of Legends","Clash Royale","Hearth Stone","Arena of Valor"};
            System.out.println(ans_str[t1+t2]);
        }
        cin.close();
    }
}

~ K. Transport Ship (差一点就做出来了TAT)

背包dp(通过率: 79.48 %,通过人数: 674)

思路:问你特定花费下多重背包方案数
首先二进制拆分物品数目变成01背包方案数
求方案数就是把max改成sum,然后dp[0]=1

// https://nanti.jisuanke.com/t/31720
#include<stdio.h>
#include<string.h>
#include<algorithm>
typedef long long ll;
const int mod=1e9+7;
ll dp[10005];
int cost[405];
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    int t;scanf("%d",&t);
    while(t--){
        int n,q,v,c;scanf("%d%d",&n,&q);
        int cnt=1;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&v,&c);
            for(int i=0;i<c;i++)
                cost[cnt++]=v,v+=v;
        }
        memset(dp,0,sizeof dp);dp[0]=1;
        for(int i=1;i<cnt;i++)
            for(int j=10000;j>=cost[i];j--)
                dp[j]=(dp[j]+dp[j-cost[i]])%mod;
        while(q--){
            scanf("%d",&c);
            printf("%lld\n",dp[c]);
        }
    }
    return 0;
}

L. Poor God Water

dp+矩阵快速幂(通过率: 88.97 %,通过人数: 750)

思路:dp[i][j][k][l]代表着已经考虑了前i个,结尾三个是jkl的方案数(实际长度是i+3)
假如说肉:1鱼:2巧克力:3
那么有如下转移
dp[i][1][2][3]=dp[i-1][1][1][2]+dp[i-1][2][1][2]+dp[i-1][3][1][2]
也就是dp[i][j][k][?]可以由dp[i-1][?][j][k]转移而来
但是有7个不合法的情况:111,222,333,132,231,313,323
所以最后就是20个状态有一个转移系数矩阵,用矩阵快速幂来求得答案
小技巧:因为会多次调用系数矩阵的2的幂次,所以可以提前处理出来系数矩阵的幂次
然后要求什么N次幂,就二进制分解把该乘的都乘起来就好了.

// https://nanti.jisuanke.com/t/31721
#include<stdio.h>
#include<string.h>
#include<map>
#define mod 1000000007
typedef long long ll;
const ll def[]={
    0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
    0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,
    1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,
    1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,
    1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,
    0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
    0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,
    0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,
    0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,
    0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,
    0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
    0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
    0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
    0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,
    0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
    0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,
    0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
    0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,
    0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,
    0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0
};
struct matrix{
    ll a[20][20];
    matrix(){
        memset(a,0,sizeof(a));
    }
    matrix(int x){
        memset(a,0,sizeof(a));
        for(int i=0;i<20;i++)
            a[i][i]=1;
    }
    matrix(const matrix&copy){
        memcpy(a,copy.a,sizeof(a));
    }
    void special(){
        memcpy(a,def,sizeof a);
    }
    ll sum(){
        ll ret=0;
        for(int i=0;i<20;i++)
            for(int j=0;j<20;j++)
                ret+=a[i][j];
        return ret%mod;
    }
    matrix operator+(const matrix&other){
        matrix ret;
        for(int i=0;i<20;i++)
            for(int j=0;j<20;j++)
                for(int k=0;k<20;k++)
                    ret.a[i][j]=(ret.a[i][j]+a[i][j]+other.a[i][j])%mod;
        return ret;
    }
    matrix operator*(const matrix&other){
        matrix ret;
        int i,j,k;
        for(i=0;i<20;i++)
            for(j=0;j<20;j++)
                for(k=0;k<20;k++)
                    ret.a[i][j]+=a[i][k]*other.a[k][j],
                    ret.a[i][j]%=mod;
        return ret;
    }
    matrix&operator*=(const matrix&other){*this=*this*other;
        return*this;
    }
    matrix operator^(ll index){
        matrix ret(1);
        matrix base(*this);
        while(index){
            if(index&1)
                ret*=base;
            base*=base;
            index>>=1;
        }
        return ret;
    }
}m,two[34];
std::map<ll,ll>map;
ll pow(ll y){
    if(map.count(y))return map[y];
    matrix ret(1);
    for(int i=0;i<34;i++)
        if(y&(1LL<<i))
            ret*=two[i];
    return map[y]=ret.sum();
}
int main(){
#ifdef LOCAL_DEBUG
    freopen("E:/ACM/SRC/1.txt","r",stdin);
#endif
    m.special();
    two[0]=m;
    for(int i=1;i<34;i++)
        two[i]=two[i-1]*two[i-1];
    int t;scanf("%d",&t);
    while(t--){
        ll x;scanf("%lld",&x);
        if(x<=3)
            switch(x){
                case 1:puts("3");break;
                case 2:puts("9");break;
                case 3:puts("20");break;
            }
        else
            printf("%lld\n",pow(x-3));
    }
    return 0;
}

发现自己真是太菜了,打~是赛后补的题.

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值