牛客练习赛76

牛客练习赛76

B zzugzx (vs) Kurisu

是一个博弈游戏
注意到(m+1)^n<=5000
那么我们是可以直接考虑爆搜的
总共N个回合,那么两个人就是2*N次操作
定义f[a][b]代表当 ,zzugzx 选了a的数,Kurisu选了b的数,zzugzx赢的概率
a和b分别是n位m+1进制的数,代表n回合他抽到1-m的数放在1~n哪个位置

#include<bits/stdc++.h>
using namespace std;
int ok[5000][5000];
double f[5000][5000];
    int n,m;
double dfs(int t,int a,int b)
{
    if(t==0)
        return a>b;
    if(ok[a][b])return f[a][b];
    ok[a][b]=1;
    if(t%2==0)
    {

        for(int i=1;i<=m;i++)
        {

            int now=a;
            int base=i;
            double maxx=0;
            for(int j=1;j<=n;j++)
            {
                if(now%(m+1)==0)maxx=max(maxx,dfs(t-1,a+base,b));//zzugzx要使自己赢得概率大
                base*=m+1;
                now/=m+1;
            }
            f[a][b]+=maxx/m*1.0;//从最大处转移

        }

    }
    else
    {
           for(int i=1;i<=m;i++)
        {

            int now=b;
            int base=i;
            double minn=1;
            for(int j=1;j<=n;j++)
            {
                if(now%(m+1)==0)minn=min(minn,dfs(t-1,a,b+base));//Kurisu要使对手输的概率大
                base*=m+1;
                now/=m+1;
            }
            f[a][b]+=minn/m*1.0;//从最小处转移

        }

    }
    return f[a][b];

}
int main()
{

    cin>>n>>m;
    printf("%.8lf\n",dfs(2*n,0,0));
}

E 牛牛数数

思路:
先求出线性基
通过贪心或者二分求出有多少个值通过线性基计算小于等于K
通过所有情况减去小于等于的情况,即为答案
注意:需要判断0的情况,线性基无法特判0
贪心:`

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll f=0;
ll p[100];
ll cnt[100];
ll tot;
void add(ll x)
{

for(ll i=62;i>=0;i--)
{

    if(x&(1ll<<i))
    {
        if(p[i]==0)
        {

            p[i]=x;
            return ;
        }
        else
        {
            x^=p[i];
        }
    }

}
  f=1;
}
void rb()
{
    for(ll i=62;i>=1;i--)
    {
        for(ll j=i-1;j>=0;j--)
        {
            if(p[i]&(1ll<<j))
            {

                p[i]^=p[j];
            }
        }
    }
    for(ll i=0;i<=62;i++)
        if(p[i])
        cnt[tot++]=p[i];
}
ll ask(ll k)
{
    ll ans=0;
    ll ct=0;
    for(ll i=tot-1;i>=0;i--)
    {
        if((ans^cnt[i])<=k)
        {
            ans^=cnt[i];

            ct+=(1ll<<i);
        }
    }
    if(f)
        ct++;
    return ct;

}
int main()
{
    cin>>n>>k;
    for(ll i=1;i<=n;i++)
    {
        ll a;
        cin>>a;
        add(a);
    }
    rb();


    cout<<(1ll<<tot)+f-1ll-ask(k)<<endl;

    return 0;
}

二分

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,tot = 0;
long long u;
long long a[1000005];
long long k[61],tt,x,cnt;
bool flag = 0;
void insert(long long x){
    for (ll i=60;i>=0;i--){
        if (x&((long long)1LL<<i)) {
            if (k[i]) x=x^k[i];
            else {
				tot++;
                k[i]=x;
                return ;
            }
        }
    }
    flag=1;
}
long long ask(long long x) {
	if (tot < n && x == 1) return 0;
	if (tot < n) x--;
	if (x >= (1LL << (long long)cnt)) return -1;
	long long ans = 0;
	for (ll i = 0;i <= 60;i++) {
		if (k[i]) {
			if (x % 2) ans ^= (long long)k[i];
			x /= 2;
		}
	}
	return ans;
}
int main(){
 	cin>>n>>u;
	for (ll i=1;i<=n;i++) {
	    cin>>a[i];
		insert(a[i]);
	}

	for (ll i = 0;i <= 60;i++) {
		for (ll j = 1;j <= i;j++) {
			if (k[i] & ((long long)1LL << (long long)(j - 1))) k[i] ^= (long long)k[j - 1];
		}
		if (k[i]) cnt++;
	}

	ll l=1,r = (1ll <<(tot))-1+flag;
	ll sum=1;
while(l<=r)
{
    ll mid=(l+r)>>1;
    if(ask(mid)>u)
    {
       r=mid-1;
        sum=mid;
    }
    else
    {
       l=mid+1;
    }
}
ll ans=1;
cout<<(1ll<<tot)+flag-sum<<endl;

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值