D题 nefu 1866 这是一道难题
思路:树状数组模板题。还有就是树状数组的单点修改只支持加减,不支持直接修改(修改时先减去原来的数,再加上修改后的数即可)。
坑的地方:没说查询时一定满足x<y!
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10,mod=1e9+7;
ll tr[N];
int n,m,a[N],x,y,opt;
void add(int i,int k)
{
while(i<=n)
{
tr[i]+=k;
i+=(i&-i);
}
}
ll sum(int i)
{
ll s=0;
while(i)
{
s+=tr[i]%mod;
i-=(i&-i);
}
return s%mod;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
add(i,a[i]);
}
while(m--)
{
scanf("%d%d%d",&opt,&x,&y);
if(opt==0)
{
add(x,-a[x]);//先减去原来的数
add(x,y);//再加上现在的数
a[x]=y;//修改原数组
}
else
{
if(x>y)swap(x,y);//巨坑!!!这个地方wa了4次!!!
printf("%lld\n",sum(y)-sum(x-1));
}
}
return 0;
}
B题 nefu 1878 Alice和Bob的分组游戏(一)
思路:sg函数打表。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10;
typedef long long ll;
bool vis[N];
int n,m,x,t;
ll sg[N],sum;
void get_sg()
{
memset(sg,0,sizeof(sg));
for(int i=2;i<=N;i++)//有i个糖果
{
memset(vis,0,sizeof(vis));
for(int j=2;j<=min(i,m);j++)//分成j堆
{
if(i%j==0)
{
t=i/j;//每堆t个
if(j&1)vis[sg[t]]=1;//奇数堆,后继状态的sg值为sg[t]
else vis[0]=1;//偶数堆,后继状态的sg值为0
}
}
for(int j=0;;j++)
if(vis[j]==0){sg[i]=j;break;}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=-1)//没有多组输入wa了一发,气死我了!
{
get_sg();sum=0;
for(int i=1;i<=n;i++)
{
cin>>x;
sum^=sg[x];
}
if(sum)printf("Alice\n");
else printf("Bob\n");
}
return 0;
}
E题 nefu 1870 这是一道签到题
思路:找规律,异或值显然与[x,y]区间长度的奇偶有关。查询时用线段树维护。
设d=y-x+1,当d为奇数时,说明x、y均为奇数或者x、y均为偶数,此时F(x,y)=a[x]^a[x+2]^…^a[y-2]^a[y](比如区间[1,5],F(1,5)=a[1]^a[3]^a[5])
当d为偶数时,F(x,y)=0恒成立。
对于d是奇数的情况,我们可以用两个线段树分别维护x、y均为奇数以及x、y均为偶数时的区间异或值。
还有,这根本就不是签到题难度啊啊啊啊!
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
ll n,d,m,x,y,opt,cnt1,cnt2,a1[N],a2[N],tre1[4*N],tre2[4*N];
void pushup(ll tr[],ll i)
{tr[i]=tr[2*i]^tr[2*i+1];}
void build(ll tr[],ll a[],ll i,ll l,ll r)
{
if(l==r){tr[i]=a[l];return;}
ll mid=l+r>>1;
build(tr,a,2*i,l,mid);
build(tr,a,2*i+1,mid+1,r);
pushup(tr,i);
}
void update(ll tr[],ll i,ll l,ll r,ll x,ll y)
{
if(x>r||x<l)return;
if(l==r&&l==x){tr[i]=y;return;}
ll mid=l+r>>1;
update(tr,2*i,l,mid,x,y);
update(tr,2*i+1,mid+1,r,x,y);
pushup(tr,i);
}
ll query(ll tr[],ll i,ll l,ll r,ll x,ll y)
{
if(l>y||r<x)return 0;
if(l>=x&&r<=y)return tr[i];
int mid=l+r>>1;
return query(tr,2*i,l,mid,x,y)^query(tr,2*i+1,mid+1,r,x,y);
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m)
{
cnt1=cnt2=0;
for(ll i=1;i<=n;i++)
{
cin>>x;
if(i&1)a1[++cnt1]=x;//a1保存下标为奇数的值(方便之后查询[x,y],x、y均为奇数的情况)
else a2[++cnt2]=x;//a2保存下标为偶数的值(方便之后查询[x,y],x、y均为偶数的情况)
}
build(tre1,a1,1,1,cnt1);//tre1保存a1数组的区间异或值
build(tre2,a2,1,1,cnt2);//tre2保存a2数组的区间异或值
for(ll i=1;i<=m;i++)
{
cin>>opt>>x>>y;
if(opt==0)
{
if(x&1)update(tre1,1,1,cnt1,(x+1)/2,y);
else update(tre2,1,1,cnt2,x/2,y);
}
else
{
if(x>y)swap(x,y);
d=y-x+1;
if(d%2==0)printf("0\n");
else
{
if(x&1)printf("%lld\n",query(tre1,1,1,cnt1,(x+1)/2,(y+1)/2));
else printf("%lld\n",query(tre2,1,1,cnt2,x/2,y/2));
}
}
}
}
return 0;
}
C题 nefu 1867 why的考号
思路:根据递推方程构造矩阵,再用矩阵快速幂。
递推方程(n>=3):f[n]=2*f[n-2]+f[n-1]+n3
设矩阵相乘等式为A*B=C,难点就是怎么去构造A矩阵。
首先,不能像我这样构造:
我们要想办法把(n+1)3用B矩阵的元素表示出来,但是这样A矩阵有一个元素[(n+1)/n]3显然是不行的(因为A矩阵中有元素[(n+1)/n]3,再快速幂误差很大)
正确做法是把(n+1)3拆开,(n+1)3=n3+3*n2+3*n+1,要想(n+1)3用B矩阵的元素表示出来,需要增添B矩阵的元素!在B矩阵下方再加三个数:n2、n、1。
那么A*B=C就变成了这样:
最后再处理一下:
OK,数学公式推导到此结束。把上面的那个最终公式推出来,代码就很好写了。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int mod=123456789;
typedef long long ll;
ll n,t,cas,ans;
struct node
{
ll m[6][6];
};
node s,
A={
0,2,0,0,0,0,
1,1,1,0,0,0,
0,0,1,3,3,1,
0,0,0,1,2,1,
0,0,0,0,1,1,
0,0,0,0,0,1};
node mul(node x,node y)//两矩阵x、y相乘
{
node s;
memset(s.m,0,sizeof(s.m));
for(int i=0;i<6;i++)
for(int j=0;j<6;j++)
for(int k=0;k<6;k++)
s.m[i][j]+=x.m[i][k]*y.m[k][j]%mod;
return s;
}
node quickpow(node a,ll b)//矩阵快速幂,求矩阵a的n次方
{
memset(s.m,0,sizeof(s.m));
for(int i=0;i<6;i++)
s.m[i][i]=1;//s初始化为单位矩阵
while(b)
{
if(b&1){b--;s=mul(s,a);}
a=mul(a,a);b=b/2;
}
return s;
}
int main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>n;
printf("Case %d: ",++cas);
if(n==1){printf("000000001\n");continue;}
s=quickpow(A,n-2);//n>=2
ans=s.m[1][0]*2%mod+s.m[1][1]*2%mod+s.m[1][2]*27%mod+s.m[1][3]*9%mod+s.m[1][4]*3%mod+s.m[1][5]%mod;
printf("%09lld\n",ans%mod);
}
return 0;
}
【未完待续。。。】