别的题没什么好说的,H正解的线段树我不会,用暴力卡过去了(数据不强)
主要说下BEF三题吧:
B
正解的思路是把转化为
我没想到这个方法,而是用打表找规律来做的:
可以发现,当n=4、13、40。。。的时候,全部都是1。而
所以首先根据 所在那一块进行分类,然后再根据更细的分类进行讨论。这里就不写细节了,毕竟推了快2小时。。
给大家介绍一下我找规律和debug的技巧。首先一定要写一个对拍函数,以及一个check函数,这样可以快速得出自己算出来的对不对。然后是不要一口气全写完,可以写一部分对拍一次,查看这一部分写的对不对,这样debug起来不容易出错。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll a[1000][1000],b[1000][1000];
ll kk;
ll f(ll n,ll m){
// cout<<n<<" "<<m<<endl;
if(m>2*n)return 0;
if(n<=kk)return a[n][m];
ll p=1,sum=0;
while(sum<n)sum+=p,p*=3;
p/=3;
ll l=sum-p,r=sum,mid=l+r+1>>1;
ll dis=n-l;
if(n==l&&n==r)return 1;
// cout<<n<<" "<<m<<" "<<dis<<endl;
if(n>=mid&&n<=r)return f(n-p,m%p);
else{
// cout<<p<<endl;
if(m<=p-1&&m>=dis*2)return 0;
if(m>n)return f(n,2*n-m);
if(m>=dis)return (3-f(n,2*dis-1-m))%3;
ll mid2=l+p/3;
// cout<<mid2<<endl;
if(n>mid2)return f(n-p/3*2,m%(p/3));
// if(n==mid2)return 1;
ll mid3=l+(p/3-(sum-p-p/3));
// cout<<mid2<<endl;
if(n>mid3)return f(n-p/3,m);
else{
// cout<<n<<" "<<m<<" "<<2*dis<<endl;
if(m>=2*dis)return 0;
return f(n-p/3,m);
}
}
}
int main(){
ll n,i,j,m,_=1;
// cin>>_;
a[0][0]=1;
a[1][0]=a[1][1]=a[1][2]=1;
for(i=2;i<300;i++){
for(j=0;j<500;j++){
a[i][j]+=a[i-1][j];
a[i][j+1]+=a[i-1][j];
a[i][j+2]+=a[i-1][j];
}
for(j=0;j<500;j++)a[i][j]%=3;
}
// cout<<f(22,9)<<endl;
kk=13;
for(i=0;i<40;i++){
// cout<<i<<": ";
for(j=0;j<2*i+2;j++){
// b[i][j]=f(i,j);
// cout<<f(i,j)<<" ";
}
// cout<<endl;
}
kk=40;
for(i=0;i<40;i++){
for(j=0;j<2*i+2;j++){
// if(b[i][j]!=f(i,j)){cout<<i<<" "<<j<<" "<<-1;return 0;}
}
}
int t;
cin>>t;
while(t--){
cin>>n>>m;
cout<<f(n,m)<<endl;
}
}
E
我们先观察第一行。
第一行第一个只能选择右和下。第一行最后一个只能选择左和下。其他的可以选择左/右和下。
那么很明显,这一行带来的权值最大的贡献(不考虑和下面的)可以用dp来解决,对应每个数选择向左/向右为 和
,就很容易解决了。
其他的行同理,列也同理。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll dp[1010][2],a[1010][1010];
int gao(int x,int y){
int p=x^y;
int i=p,cnt=0;
while(i)cnt+=i%2,i/=2;
return p+cnt;
}
int main(){
ll n,i,j=0,k,z=0,sum=0,cnt=0;
ll m;
cin>>n>>m;
for(i=0;i<n;i++){
for(j=0;j<m;j++){
cin>>a[i][j];
}
}
ll ans=0;
for(i=0;i<n;i++){
for(j=0;j<m;j++)dp[j][0]=dp[j][1]=0;
dp[1][1]=gao(a[i][0],a[i][1]);
for(j=2;j<m;j++){
dp[j][0]=max(dp[j-1][0],dp[j-1][1]);
dp[j][1]=max(dp[j-2][0],dp[j-2][1])+gao(a[i][j],a[i][j-1]);
}
// cout<<max(dp[m-1][0],dp[m-1][1])<<endl;
ans+=max(dp[m-1][0],dp[m-1][1]);
}
for(j=0;j<m;j++){
for(i=0;i<n;i++)dp[i][0]=dp[i][1]=0;
dp[1][1]=gao(a[0][j],a[1][j]);
for(i=2;i<n;i++){
dp[i][0]=max(dp[i-1][0],dp[i-1][1]);
dp[i][1]=max(dp[i-2][0],dp[i-2][1])+gao(a[i][j],a[i-1][j]);
// cout<<i<<" "<<j<<" "<<dp[i][0]<<" "<<dp[i][1]<<endl;
}
// cout<<max(dp[n-1][0],dp[n-1][1])<<endl;
ans+=max(dp[n-1][0],dp[n-1][1]);
}
cout<<ans;
}
F
这道题有很多人是OEIS过的,我说一下我的推导过程。
首先要明确两个公式:
(这个公式可以用上一个公式推出)
然后推导的时候为了方便,可以拿具体的数为例子(本题用12进行推导)。
设
那么有:
由于上述推导过程适用于任何正整数 不仅仅是12,所以可以得出递推式:
用这个递推式继续化简:
………………①式
………………②式
………………③式
……………………
其中,假设已知f(4),那么可以用①式推出f(8),②式推出f(12)。。。以此类推可以推出所有的f(n)了
#include<bits/stdc++.h>
using namespace std;
#define ll long long
string s[1010];
ll dp[100010];
int mod=998244353;
ll power(ll a,ll b){
ll res=1;
while(b){
if(b&1)res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
int main(){
ll n,i,j,k,t,m,sum=0;
//2^(n-2)-或+2*(n/2)+
cin>>n;
cout<<((power(2,n-2)+(n%8!=0?-1:1)*power(2,n/2)-(n%8!=0?-1:1)*power(2,n/2-1))%mod+mod)%mod;
}

京公网安备 11010502036488号