牛客 —— 6th
传送门
B. Binary Vector
题意
给出随机的\(N\)个\(01\)向量,求出这\(N\)个向量线性无关的概率\(f(n)\),求出\(f(1) \oplus f(2) \dots \oplus f(n)\)
数据范围
\(1\leq T\leq 1000\)
\(1\leq N \leq 2 \times 10^{7}\)
题解
线性空间中的零向量表示与任意向量做向量加法和标量乘法后向量不变的量,如果存在零向量那么这个线性空间必定是线性相关的
所以要排除掉全\(0\)的\(N\)维向量,每一步都减去固定位数的所有可能取值个数,得到式子如下
求出\(2\)关于\(mod=10^{9}+7\)的逆元,然后打表每个\(f(i)\)的值
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define close ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define ll long long
const int mod=1e9+7;
const int N=2e7+10;
int f[N];
int _;
int inv2=mod+1>>1;
void solve(){
ll now=1;
f[0]=1;
rep(i,1,N){
now=now*inv2%mod;
f[i]=f[i-1]*(1-now+mod)%mod;
}
rep(i,2,N) f[i]^=f[i-1];
}
int main(){
close
cin>>_;
solve();
while(_--){
int n;cin>>n;
cout<<f[n]<<endl;
}
}
C. Combination of Physics and Maths
题意
给定一个\(N\)行,\(M\)列的矩阵,求子矩阵的和除这个子矩阵最后一行的和最大值
数据范围
\(1\leq N,M\leq 200\)
\(1\leq a_{i,j} \leq 5\times 10^{4}\)
题解
贪心只需要考虑一列的压强即可,假如\(\frac{a}{b} < \frac{c}{d}\),那么必有\(\frac{a}{b}<\frac{a+c}{b+d}<\frac{c}{d}\)
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define db double
const int N=210;
int a[N][N];
int n,m;
int _;
int main(){
for(scanf("%d",&_);_;_--){
scanf("%d%d",&n,&m);
rep(i,0,n) rep(j,0,m) scanf("%d",&a[i][j]);
db ans=-1e3;
rep(j,0,m){
db sum=0;
rep(i,0,n){
sum+=a[i][j];
ans=max(ans,sum/a[i][j]);
}
}
printf("%.8lf\n",ans);
}
}
E.Easy Construction
题意
给定一个\(N,P\),构造一个\(1\sim N\)的排列,使得长度为\(i\in [1,N]\) 的连续子序列的和\(mod \; N = P\)
数据范围
\(1\leq N\leq 5000\)
\(1\leq P < N\)
题解
先判断一下当前\(N\)个数的和模\(N\)是否满足,不满足直接输出-1
如果满足,判断\(k\)为0的情况,
- 不为0,输出k
- 为0不操作
然后以\(k\)为中心向两边走即可,最后判断是否有剩下的即可
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
int n,k;
int sum=0;
int main(){
scanf("%d%d",&n,&k);
rep(i,1,n+1) sum+=i;
if(sum%n != k) {
puts("-1");
return 0;
}
int i=1;
int rec=n;
printf("%d ",n);
rec--;
if(k!=0){
printf("%d ",k);
rec--;
}
while(rec) {
printf("%d ",k+i);
printf("%d ",n-k-i);
i++;
rec-=2;
}
if(rec) printf("%d ",k+i);
}
K.K-bag
题意
多组样例,给定长度为\(N\)的序列\(A\),以及一个数\(K\)表示\(i\)
数据范围
\(5\leq n\leq 10^{5}\)
\(1\leq k\leq 10^{9}\)
题解
\(k-bag\) 的子串只能在首尾处不是\(1\sim k\)的排列,形式为\(x k k \dots k k x\),
从头部找到第一次重复出现的两个值的下标,从第一个开始向后进行移动,要判断当前字符重复次数是否合法,
如果不合法就移动左端点,如果左指针超过了第一次出现重复值的右断点, 说明当前枚举的区间不是一个\(k\)排列不合法
否则如果当前等于就右移判断
Code
cpp
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define close ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define ll long long
const int N=5e5+10;
int _;
int a[N];
bool check(int x,int k){
return x>=1 && x<=k;
}
void solve(){
int n,k;
cin>>n>>k;
bool ok=1;
rep(i,1,n+1) {
cin>>a[i];
if(!check(a[i],k)) ok=0;
}
if(!ok){cout<<"NO"<<endl; return;}
map<int,int>mp;
int lfi=-1,rfi=-1;
rep(i,1,n+1){
if(mp[a[i]]){
lfi=mp[a[i]];
rfi=i;
break;
}
mp[a[i]]=i;
}
if(lfi==-1){
cout<<"YES"<<endl;
return;
}
mp.clear();
int l=lfi+1,r=lfi+1;
int t=0;
int cnt=0;
ok=1;
while(1){
if(l > rfi){
ok=0;
break;
}
while(r<=n && cnt<k){
if(mp[a[r]] == t){
mp[a[r]]++;
r++;
cnt++;
}
else {
mp[a[l]]--;
cnt--;
l++;
break;
}
}
if(cnt==k) {cnt=0;t++;}
if(r>n) break;
}
if(ok) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
int main(){
close
cin>>_;
while(_--)
solve();
return 0;
}