2019.7.10 牛客小白赛 小a与星际探索(异或,dp) 小a与黄金街道(欧拉函数,数学)拓展欧拉定理

小a与星际探索

题目意思就是 给n个星球的能量ai
第一个能量是飞船的初始能量,飞船要从i星球到j星球,必须满足a[i]>a[j],并且飞船能量会变成 现在飞船能量 异或 a[j]。
飞船要到第n个星球,求飞船的最大能量。

一开始接触这题,小白赛嘛
打完后有人在群里说线性基线性基
当时晓得个锤子

现在来试试

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[3500],p[100],b[3005];
void get(int x){
	for(int i=62;i>=0;i--){
		if(!(x>>i)){
			continue;
		}
		if(!p[i]){
			p[i]=x;
			break;
		}
		x^=p[i];
	}
}
int main(){
	int n,cnt=0;
	int ans=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&b[i]);
	}
	int first=b[1];
	if(b[1]<=b[n]){
		printf("-1");
		return 0;
	}
	for(int i=2;i<=n-1;i++){
		if(b[i]>first){
			a[cnt++]=b[i];
		}
	}
	for(int i=0;i<cnt;i++){
		get(a[i]);
	}
	ans=b[1]^b[n];
	for(int i=62;i>=0;i--){
		if((ans^p[i])>ans){
			ans^=p[i];
		}
	}
	if(ans==0){
		printf("-1");
	}else 
	printf("%d",ans);
	return 0;
}

硬套模板过不了
可能是ans原本就要是0
还是不太理解线性基

就说说正解

首先进行排序
如果第一个星球值小于等于最后一个,直接输出

然后从大到小排序完去从id为1的开始处理到id为n的,因为异或满足结合律
即a ^ (b ^c)=(a ^ b) ^ c

所以我们可以枚举答案,从1<<12-1开始,(为啥是212-1呢?因为4096是大于3000的第一个2的x次方数,所以答案最大只有可能是4095)

然后就是dp了,dp记录的其实用bool就好 ,意义是dp[i]代表飞船的能量能否到达i

#include<bits/stdc++.h>
using namespace std;
const int N=3e3+100;
const int M=1<<12;
int n,ans,tot,dp[M],p[N],a[N];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&p[i]);
    }
    for(int i=2;i<=n-1;i++){
        if(p[1]>p[i]&&p[i]>p[n])
            a[tot++]=p[i];
    }
    dp[p[1]^p[n]]=1;
    for(int i=0;i<tot;i++){
        for(int j=M-1;j>=0;j--){
            dp[j]|=dp[j^a[i]];
        }
    }
    for(int i=M-1;i>=0;i--){
        if(dp[i]) {ans=i;break;}
    }
    ans=p[1]<=p[n]?-1:ans;
    return printf("%d\n",ans)*0;
}

代码出自https://blog.csdn.net/Z_sea/article/details/86600771
这个return 赞一个,很秀
为啥是dp[j]|=dp[j^a[i]]呢?因为j ^ a[i]=x的话 那么 x ^ a[i] =j

就是说我们穷举j就是穷举可能的答案,
就是如果飞船能到j,那么必定存在x使得x ^ a[i] =j,所以dp[x]和dp[j]是相同的。

用这种方法就可以了

我们再来看一道题

前置知识:欧拉函数

φ函数的值  通式:φ(x)=x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)……(1-1/pn),其中p1, p2……pn为x的所有质因数,x是不为0的整数。φ(1)=1(唯一和1互质的数(小于等于1)就是1本身)。 (注意:每种质因数只一个。比如12=223那么φ(12)=12*(1-1/2)*(1-1/3)=4)
   ----摘自百度
另外一篇博客

欧拉函数的性质

接下来怎么求欧拉函数呢

LL mul(LL x, LL y,LL p) {
	LL ans=0;
	while(y){
		if(y&1)ans+=x%p;
		y>>=1;
		x+=x%p;
	}
    return ans ;
}
LL Phi(LL N) {
    LL ans = 1;
    for(LL i = 2; i * i <= N; i++) {
        if(!(N % i)) {
            ans = mul(ans, i - 1); N /= i;
            while(!(N % i)) ans *= i, N /= i;
        }
    }
    if(N ^ 1) ans *= N - 1;//n是否为1
    return ans;
}

O(根号n)的复杂度,加上位运算
是我见过挺好的模板

小a与黄金街道
反正意思就不说了
挺巧妙的

1-n的所有gcd(n,x)==1的所有x数的和为n*φ(n)/2
牛客上的题解有说怎么来的

所以呢
这题套公式就好了

#include<bits/stdc++.h>
#define LL long long
#define int long long  
using namespace std;
const LL mod = 1e9 + 6, mod2 = mod + 1;
LL N, K, A, B;
LL add(LL x, LL y) {
    if(x + y < 0) return x + y + mod;
    return x + y >= mod ? x + y - mod : x + y;
}
LL mul(LL x, LL y) {
    return 1ll * x * y % mod;
}
LL fp(LL a, LL p, LL mod) {
	p %= mod;
    LL base = 1;
    while(p) {
        if(p & 1) base = base * a % mod;
        a = a * a % mod; p >>= 1;
    }
    return base;
}
LL Phi(LL N) {
    LL ans = 1;
    for(LL i = 2; i * i <= N; i++) {
        if(!(N % i)) {
            ans = mul(ans, i - 1); N /= i;
            while(!(N % i)) ans *= i, N /= i;
        }
    }
    if(N ^ 1) ans *= N - 1;
    return ans;
}
signed main() {
    cin >> N >> K >> A >> B;
    LL Lim = 1e13;
    assert(A >= 1 && A <= Lim && B >= 1 && B <= Lim);
    LL tmp = ((N % mod) * ((Phi(N) / 2) % mod) % mod) ;
    LL ans = (A + B) % mod2 * fp(K % mod2, tmp, mod2) % mod2;
    cout << ans;
    return 0;
}

这个signed main也很秀
long long 不能作为主函数类型,而防止int溢出,很秀的操作

assert终止函数

在这里插入图片描述

这是个拓展欧拉定理,吉比特杯学到的

因为Phi(1e9+7)=1e9+6
所以那个指数模的就是1e9+6

原来如此

今儿就到这

发布了61 篇原创文章 · 获赞 8 · 访问量 2471

猜你喜欢

转载自blog.csdn.net/weixin_43982216/article/details/95361661