layout: post
title: “字节跳动-文远知行杯”广东工业大学第十四届程序设计竞赛
author: "luowentaoaa"
catalog: true
mathjax: true
tags:
- 数学
- 矩阵快速幂
- 权值线段树
hzy 和zsl 的生存挑战 (签到)
我还是要吐槽一下,题目都说了两人没有交流还怎么能推出一个人相同一个人不相同,如果两个人都相同呢?
puts("1.00
1.00
1.00
1.00");
return 0;
}
人类史上最大最好的希望事件 (矩阵快速幂求fib前缀平方和)
思路
斐波那契数列前n项和答案为(F_{N}*F_{N+1})
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pp pair<int,int>
const ll mod=192600817;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
ll x,y;
typedef vector<ll>vec;
typedef vector<vec>mat;
mat mul(mat& A,mat &B){
mat C(A.size(),vec(B[0].size()));
for(int i=0;i<A.size();i++)
for(int k=0;k<B.size();k++)
if(A[i][k])
for(int j=0;j<B[0].size();j++)
C[i][j]=(C[i][j]+A[i][k]*B[k][j]%mod+mod)%mod;
return C;
}
mat Pow(mat A,ll n){
mat B(A.size(),vec(A.size()));
for(int i=0;i<A.size();i++)B[i][i]=1;
for(;n;n>>=1,A=mul(A,A))
if(n&1)B=mul(B,A);
return B;
}
int main(){
int q;
while(~scanf("%d",&q)){
for(int i=1;i<=q;i++){
ll a,b,c,d;
scanf("%lld %lld %lld %lld",&a,&b,&c,&d);
a=a*4+b+1;b=c*4+d+1;
if(a>b)swap(a,b);
a--;
mat A(2,vec(2)),B(2,vec(2)),F1(2,vec(1)),F2(2,vec(1));
A[0][0]=A[0][1]=A[1][0]=1;A[1][1]=0;
F1[0][0]=1;F1[1][0]=0;
B[0][0]=B[0][1]=B[1][0]=1;B[1][1]=0;
F2[0][0]=1;F2[1][0]=0;
A=Pow(A,a);
B=Pow(B,b);
F1=mul(A,F1);
F2=mul(B,F2);
ll ans1=F1[0][0]*F1[1][0]%mod;
ll ans2=F2[0][0]*F2[1][0]%mod;
printf("%lld
",(ans2-ans1+mod)%mod);
}
}
return 0;
}
超级无敌简单题 (规律)
思路
发现如果出现4就会出现死循环
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll mod=1e8+7;
const int maxn=5e5+50;
const int inf=1e8;
vector<int>ve;
bool isok(int n){
while(n!=1&&n!=4){
ll sum=0;
while(n){
sum+=(n%10)*(n%10);
n/=10;
}
n=sum;
}
return n==1;
}
int main()
{
int q;
for(int i=1;i<1100000;i++){
if(isok(i))ve.push_back(i);
}
//cout<<ve.size()<<endl;
/*for(int i=0;i<ve.size();i++){
cout<<ve[i]<<endl;
}*/
scanf("%d",&q);
while(q--){
int n;
scanf("%d",&n);
printf("%d
",ve[n-1]);
}
return 0;
}
免费送气球 (权值线段树)
思路
对于每个数存一个数量和val 然后判断数量是否大于查询数量,
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e16;
const ll mod=1e9+7;
const int maxn=1e5+50;
ll sum[maxn*40],val[maxn*40];
int ls[maxn*40],rs[maxn*40];
int cnt;
void update(int &o,int l,int r,int k,int num){
if(!o)o=++cnt;
sum[o]+=k;
val[o]+=1LL*k*num;
val[o]%=mod;
if(l==r)return;
int mid=(l+r)/2;
if(num<=mid)update(ls[o],l,mid,k,num);
else update(rs[o],mid+1,r,k,num);
}
ll query(int o,int l,int r,ll k){
if(l==r)return 1LL*k*l%mod;
int mid=(l+r)/2;
ll res=0;
if(k>sum[ls[o]])res=(val[ls[o]]+query(rs[o],mid+1,r,k-sum[ls[o]]));
else res=query(ls[o],l,mid,k);
return res%mod;
}
int main()
{
int q,rt=0;
cin>>q;
while(q--){
int op;ll l,r;
cin>>op>>l>>r;
if(op==1)update(rt,0,1e9,l,r);
else{
cout<<(query(rt,0,1e9,r)-query(rt,0,1e9,l-1)+mod)%mod<<endl;
}
}
return 0;
}
简单数学题 (数学题)
思路
(F(n) = sum_{i=1}^n (i imes sum_{j=i}^n C_j^i))
->$F(n)=sum_{i=1}{n}sum_{j=i}{n} i imes C_{j}^{i} $
其中$ sum C_{j}^{i}$ 是杨辉三角的一条斜线
然后把i乘入这个斜线中,发现杨辉三角变成一个新的少了一维的杨辉三角
发现新的杨辉三角是之前的杨辉三角每一层的元素乘上层号
然后就是变成求(sum_{i=1}^{n} i imes 2^{i-1})
(1 imes 2+2 imes2^1 +3 imes 2^2+dots n imes2^{n-1})
然后拆项为
根据等比数列(s_n=frac{a_1(1-a_n)}{1-q}=frac{a_nq-a_1}{q-1})
整理
第一行变成(2^n-2^0) 第二行变成(2^n-2^1) 第n行变成(2^n-2^{n-1})
再整理变成(n imes2^n-(2^n-1)=(n-1) imes2^n+1)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll mod=1e9+7;
const int maxn=5e5+50;
const int inf=1e8;
ll ksm(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
int main()
{
ll n;
while(~scanf("%lld",&n)){
ll ans=ksm(2,n);
n%=mod;
ans=(ans*(n-1))%mod;
ans+=1;ans%=mod;
printf("%lld
",ans);
}
return 0;
}
zyb的面试 (原题)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll mod=1e9+7;
const int maxn=1e3+50;
const ll inf=1e17;
int cal(int n,int k){
int cur=1;
k=k-1;
while(k>0){
int step=0,first=cur,last=cur+1;
while(first<=n){
step+=min(n+1,last)-first;
first*=10;
last*=10;
}
if(step<=k){
cur++;
k-=step;
}
else{
cur*=10;
k-=1;
}
}
return cur;
}
int main()
{
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
cout<<cal(n,k)<<endl;
}
return 0;
}
Count (矩阵快速幂)
思路
考虑矩阵快速幂 考虑要从前一项得到后一项的(n^3)
根据公式((n+1)^3=n^3+3*n^2+3*n+1)
推出(f(n)=f(n-1)+2*f(n-2)+n^3+3*n^2+3*n+1)
所以构造一个矩阵就行了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pp pair<int,int>
const ll mod=123456789;
const int maxn=1e6+50;
const ll inf=0x3f3f3f3f3f3f3f3fLL;
#define bug cout<<"here"<<endl;
typedef vector<ll>vec;
typedef vector<vec>mat;
mat mul(mat& A,mat &B){
mat C(A.size(),vec(B[0].size()));
for(int i=0;i<A.size();i++)
for(int k=0;k<B.size();k++)
if(A[i][k])
for(int j=0;j<B[0].size();j++)
C[i][j]=(C[i][j]+A[i][k]*B[k][j]%mod+mod)%mod;
return C;
}
mat Pow(mat A,ll n){
mat B(A.size(),vec(A.size()));
for(int i=0;i<A.size();i++)B[i][i]=1;
for(;n;n>>=1,A=mul(A,A))
if(n&1)B=mul(B,A);
return B;
}
int main(){
int q;
scanf("%d",&q);
while(q--){
ll n;
scanf("%lld",&n);
if(n==1){
printf("1
");continue;
}
else if(n==2){
printf("2
");continue;
}
mat a(6,vec(6));
a[0][0]=1;a[0][1]=2;a[0][2]=1;a[0][3]=3;a[0][4]=3;a[0][5]=1;
a[1][0]=1;a[1][1]=0;a[1][2]=0;a[1][3]=0;a[1][4]=0;a[1][5]=0;
a[2][0]=0;a[2][1]=0;a[2][2]=1;a[2][3]=3;a[2][4]=3;a[2][5]=1;
a[3][0]=0;a[3][1]=0;a[3][2]=0;a[3][3]=1;a[3][4]=2;a[3][5]=1;
a[4][0]=0;a[4][1]=0;a[4][2]=0;a[4][3]=0;a[4][4]=1;a[4][5]=1;
a[5][0]=0;a[5][1]=0;a[5][2]=0;a[5][3]=0;a[5][4]=0;a[5][5]=1;
mat f(6,vec(1));
f[0][0]=2;
f[1][0]=1;
f[2][0]=8;
f[3][0]=4;
f[4][0]=2;
f[5][0]=1;
a=Pow(a,n-2);
f=mul(a,f);
printf("%lld
",f[0][0]);
}
return 0;
}