牛客练习赛23题解

A 托米的赌球【贪心】
模拟,从最大的钱数直接贪心来。

#include
using namespace std;
#define ll long long int
ll a[15]={10000,5000,2000,1000,500,200,100,50,20,10,5,2,1};
ll vis[15];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--){
        ll x,y;
        scanf("%lld %lld",&x,&y);
        x=x*100+y;
        memset(vis,0,sizeof vis);
        for(int i=0;i<13;i++){
            while(x-a[i]>=0){
                vis[i]++;
                x-=a[i];
            }
        }
        for(int i=0;i<13;i++){
            if(i) printf(" ");
            printf("%lld",vis[i]);
        }
        printf("\n");
    }
    return 0;
}

B 托米的划分【记忆化||贪心】
每次划1是最优的,直接记忆化也OK。

#include
using namespace std;
#define ll long long int
ll a[15]={10000,5000,2000,1000,500,200,100,50,20,10,5,2,1};
ll vis[15];
int main()
{
    ll ans=0;
    int T;
    scanf("%d",&T);
    while(T--){
        ll n;
        scanf("%lld",&n);
        ans=(n*(n-1))/2;
        printf("%lld\n",ans);
    }
    return 0;
}

C 托米的位运算【枚举lowbit】
来看一下,某一位能否被构造出来,按照题目要求取最优解。

#include
using namespace std;
#define ll long long int
#define lowbit(x) (x&(-x))
const int maxn=1e5+2333;
int  a[maxn];
int vis[maxn];
int p[35];
int n;
int main()
{
    scanf("%d",&n);
    p[0]=p[1]=1;
    for(int i=2; i<=31; i++) p[i]=p[i-1]*2;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
    }
    int ans=0;
    int cs=0;
    int x;
    int tmp=0;
    int cz=0;
    for(int i=31; i>=1; i--)
    {
        tmp=0;
        cz=0;int flag=0;
        for(int j=1; j<=n; j++)
        {
            if(a[j]&p[i])
            {
                if(!flag) tmp=a[j],flag=1;
                else tmp=tmp&a[j];
                cz++;
               // cout<<1<
            }
        }
        //cout<
        if(lowbit(tmp)==p[i])
        {
            tmp=0;
            cz=0;
            cs=0;flag=0;
            for(int j=1; j<=n; j++)
            {
                if(a[j]&p[i])
                {
                    vis[++cs]=j;
                    if(!flag) tmp=a[j],flag=1;
                    else tmp=tmp&a[j];
                }
            }
            break;
        }
    }
    printf("%d\n",cs);
    for(int i=1;i<=cs;i++){
        if(i^1) printf(" ");
        printf("%d",a[vis[i]]);
    }



    return 0;
}

D 托米的咒语【全排列+二分】
把每一种字母出现的所有位置都记录下来,然后枚举全排列,根据每一种情况,二分查找下一个放的字母的位置,如果所有字母全都能找到的话ans++。

#include
using namespace std;
const int maxn=3e3+25;
char s[maxn];
int a[maxn];
int cnt[12][maxn];
int vis[12];
int x[10];
int main()
{
    memset(vis,0,sizeof vis);
    scanf("%s",s);
    int len=strlen(s);
    for(int i=0;i1]=(s[i]-'a')+1;
    }
    for(int i=1;i<=len;i++){
        cnt[a[i]][++vis[a[i]]]=i;
    }
    for(int i=0;i<9;i++) x[i]=i+1;
    int ans=0;
    do{
        int tmp=0;bool flag=1;
        for(int i=0;i<9;i++){
            tmp=upper_bound(cnt[x[i]]+1,cnt[x[i]]+1+vis[x[i]],tmp)-cnt[x[i]];
            if(tmp>vis[x[i]]) {flag=0;break;}
            tmp=cnt[x[i]][tmp];
        }
        if(flag) ans++;
        //cout<

    }while(next_permutation(x,x+9));
    printf("%d\n",ans);
    return 0;
}

E 托米的数学【欧拉函数||费马小定理】
题目中给出的数字是“走马灯数”,是非常有趣的一种数字。

有关知识和这个题的结论参考自:
https://zhuanlan.zhihu.com/p/27853213

#include
using namespace std;
#define ll long long int
#define INF 0x3f3f3f3f
#define clr(x,y) memset(x,y,sizeof x);
const int maxn=2e4+23;
bool ispri(ll x){
    for(ll i=2;i*i<=x;i++){
        if(x%i==0) return 0;
    }
    return 1;
}
ll qkm(ll a,ll b,ll p){
    ll ans=1;
    while(b>0){
        if(b%2){
            ans=ans*a;ans%=p;
        }
        a=a*a;a%=p;b>>=1;
    }
    return ans;
}
ll judge(ll x,ll p){
    for(ll i=2;i*i<=p-1;i++){
        if((p-1)%i==0){
            if(qkm(x,i,p)==1||qkm(x,(p-1)/i,p)==1){
                return 0;
            }
        }
    }
    return 1;
}
ll n,x;
int main()
{
    cin>>n>>x;
    if(ispri(n+1)){
        for(ll i=x-1;i>=2;i--){
            if(judge(i,n+1)){
                printf("%d\n",i);
                return 0;
            }
        }
    }
    puts("-1");
    return 0;
}

F 托米的游戏【树形DP期望】
期望和树的层数有关,也和每一层的节点个数有关。经过测试和推导发现,答案是所有节点深度之和的一半,在取模意义下通过费马小定理解决除法问题。

#include
using namespace std;
#define ll long long int
#define lowbit(x) (x&(-x))
const int maxn=1e5+2333;
int  a[maxn];
int vis[maxn];
int p[35];
int n;
int main()
{
    scanf("%d",&n);
    p[0]=p[1]=1;
    for(int i=2; i<=31; i++) p[i]=p[i-1]*2;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
    }
    int ans=0;
    int cs=0;
    int x;
    int tmp=0;
    int cz=0;
    for(int i=31; i>=1; i--)
    {
        tmp=0;
        cz=0;int flag=0;
        for(int j=1; j<=n; j++)
        {
            if(a[j]&p[i])
            {
                if(!flag) tmp=a[j],flag=1;
                else tmp=tmp&a[j];
                cz++;
               // cout<<1<
            }
        }
        //cout<
        if(lowbit(tmp)==p[i])
        {
            tmp=0;
            cz=0;
            cs=0;flag=0;
            for(int j=1; j<=n; j++)
            {
                if(a[j]&p[i])
                {
                    vis[++cs]=j;
                    if(!flag) tmp=a[j],flag=1;
                    else tmp=tmp&a[j];
                }
            }
            break;
        }
    }
    printf("%d\n",cs);
    for(int i=1;i<=cs;i++){
        if(i^1) printf(" ");
        printf("%d",a[vis[i]]);
    }



    return 0;
}

你可能感兴趣的:(Contest)