Codeforces Round #473 (Div. 2) D 数学,贪心 F 线性基,模板
D. Mahmoud and Ehab and another array construction task
题意:
给出一个数组 a[],要你构造出一个互质的字典序最小的数组 b[],且 b[] 的字典序要大于等于 a[] 。
tags:
预处理出 1e5 个素数,然后对于第 i 个数,它应该不包含前面 n-1 个数含有的质因子,满足这个条件后,我们贪心取最大的即可。且如果当前已经大于数组 a[] 了,那后面的就都贪心取最小的质数。
// CF 959D
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi first
#define se second
typedef long long ll;
const int N = 20000005;
const int M=2000005; // M : size
bool mark[M]; // true : prime number
int pp[N], cnt;
void sieve_prime()
{
memset(mark, true, sizeof(mark));
mark[0] = mark[1] = false;
for(int i=2; i<=sqrt(M); i++) {
if(mark[i]) {
for(int j=i*i; j<M; j+=i)
mark[j]=false;
}
}
rep(i,2,M-1) if(mark[i]) pp[++cnt] = i;
}
int n, a[N], b[N];
bool vis[M];
void get(int x) {
for(int i=1; i<=cnt && pp[i]<=x; ++i) {
while(x%pp[i]==0) vis[pp[i]]=true, x/=pp[i];
}
}
bool is(int x) {
for(int i=1; i<=cnt && pp[i]<=x; ++i)
if(vis[pp[i]])
{
if(x%pp[i]==0) return false;
}
return true;
}
int main()
{
sieve_prime();
scanf("%d", &n);
rep(i,1,n) scanf("%d", &a[i]);
bool flag = false;
int ca = 1;
rep(i,1,n)
{
if(flag) {
for( ; vis[pp[ca]]; ++ca) ;
vis[pp[ca]]=true;
b[i] = pp[ca];
continue;
}
if(i==1) b[1]=a[1], get(b[1]);
else {
for(int j=a[i]; ; ++j)
if(is(j))
{
get(j); b[i]=j;
if(j>a[i]) flag = true;
break;
}
}
}
rep(i,1,n) printf("%d ", b[i]);
return 0;
}
F. Mahmoud and Ehab and yet another xor task
题意:
n 个数,q 个询问,每次询问有 l, x 。 询问前 l 个数里,有多少个子序列的异或和为 x 。
tags:
第一次见线性基的问题。。很有意思。
参考了博客 https://blog.csdn.net/qaq__qaq/article/details/53812883
我们把询问按 l 排序,对于每个询问我们把 a[1] ~ a[l] 都插入到线性基里。首先看线性基能否异或出 x ,然后看线性基里有几个数,如有 k 个数,那答案就是 2^(l-k) 。
可以这样考虑,如果线性基可以异或出 x ,线性基里有 k个数,那在另外 l - k 个数里取出一个数 y ,我们对于 y 取或不取有两种可能。如取 y ,那只要异或出 x 即可;如不取 y ,那就异或出 x^y 即可(肯定可以异或出 x^y 的,因为线性基的异或域和原序列的异或域相同)。
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi first
#define se second
typedef long long ll;
const int N = 200005, mod = 1e9+7;
ll fpow(ll a, ll b) {
ll ret = 1;
for(a%=mod; b; b>>=1, a=a*a%mod) if(b&1) ret = ret*a%mod;
return ret;
}
struct L_B
{
long long d[61], p[61];
int cnt;
L_B() {
memset(d,0,sizeof(d));
memset(p,0,sizeof(p));
cnt=0;
}
bool Insert(long long val) { //插入
for (int i=60;i>=0;i--)
if (val&(1LL<<i)) {
if (!d[i]) { d[i]=val; break; }
val ^= d[i];
}
return val>0;
}
bool is_in(long long val) { //存在性
for(int i=60; i>=0; --i) {
if(val&(1LL<<i)) {
if(d[i]) val ^= d[i];
}
}
return val==0;
}
long long query_max() { //最大值
long long ret=0;
for (int i=60;i>=0;i--)
if ((ret^d[i])>ret)
ret^=d[i];
return ret;
}
long long query_min() { //最小值
for (int i=0;i<=60;i++)
if (d[i]) return d[i];
return 0;
}
void rebuild() { //求 k 小值前加
for (int i=60;i>=0;i--)
for (int j=i-1;j>=0;j--)
if (d[i]&(1LL<<j))
d[i]^=d[j];
for (int i=0;i<=60;i++)
if (d[i]) p[cnt++]=d[i];
}
long long kthquery(long long k) { //k小值
long long ret=0;
if (k>=(1LL<<cnt))
return -1;
for (int i=60;i>=0;i--)
if (k&(1LL<<i))
ret^=p[i];
return ret;
}
} LB;
L_B merge(const L_B &n1,const L_B &n2) //合并
{
L_B ret=n1;
for (int i=60;i>=0;i--)
if (n2.d[i])
ret.Insert(n2.d[i]);
return ret;
}
int a[N];
ll ans[N];
pair< int, pair< int , int > > Q[N];
int main()
{
int n, q; scanf("%d%d", &n, &q);
rep(i,1,n) scanf("%d", &a[i]);
rep(i,1,q) scanf("%d%d", &Q[i].fi, &Q[i].se.fi), Q[i].se.se=i;
sort(Q+1, Q+1+q);
int now = 1;
rep(i,1,q)
{
for( ; now<=Q[i].fi; ++now) LB.Insert(a[now]);
if(!LB.is_in(Q[i].se.fi)) {
ans[Q[i].se.se] = 0;
continue;
}
int cnt = 0;
per(j,60,0) if(LB.d[j]) ++cnt;
ans[Q[i].se.se] = fpow(1LL*2, Q[i].fi-cnt);
}
rep(i,1,q) printf("%lld\n", (ans[i]+mod)%mod);
return 0;
}