wxy 3.29 牛客练习赛52重现
v>
5057
B
对于树状数组的理解,add不仅仅是加,可以为减,就是如果一个区间内莫格数不要的话,可以在相应
的位置上add原来的负数
求区间的和,如果一个数在该区间上出现多次,那么只加一次
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=5e5+100;
LL c[MAXN],a[MAXN]; //a原数组 c求和后数组
int lowbit(int x){ return x&(-x); }
int n,m;
void add(int x,LL y) //x更新位置 y为更新后的数
{
for(int i=x;i<=n;i+=lowbit(i)){
c[i]+=y;
}
return ;
}
LL sum(int x) //1-x 求和
{
LL ans=0;
for(int i=x;i;i-=lowbit(i)){
ans+=c[i];
}
return ans;
}
struct Node{
int l,r,id;
LL ans;
}node[MAXN];
int pre[MAXN];
int cmp(Node a,Node b) { return a.r<b.r; }
int cmp1(Node a,Node b) { return a.id<b.id; }
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&node[i].l,&node[i].r);
node[i].id=i;
node[i].ans=0;
}
sort(node+1,node+m+1,cmp);
int cnt=1;
for(int i=1;i<=n;i++){C
设f[ i ] [ j ]表示前i项gcd为j的序列有多少个,有两个来源,一个f[ i-1 ] [ j ],一个是 f [ i - 1 ] [ k ]
(gcd(k,a[i])==j) ,所以可以变换为 f [ i ] [ j ]+=f[ i - 1 ] [ j ] , f[ gcd(j,a[i])]+=f[i-1] [ j ],感觉有点奇怪,递
推方程到代码的联系不是那么直接
还有一种思路,类似于背包
就是f[i]表示gcd为i的个数,相当于从n个数中取m个数,使得gcd为i放到f[i]中,每种数只能取一个,有
点类似于01背包,但是因为不是取体积为v所以不是倒序遍历的。而且因为回有f[gcd(i,i)]所以方案数还
要除以2
if(pre[a[i]]) add(pre[a[i]],-a[i]);
pre[a[i]]=i;
add(i,a[i]);
while(i==node[cnt].r&&cnt<=m){
node[cnt].ans=sum(node[cnt].r)-sum(node[cnt].l-1);
cnt++;
}
}
sort(node+1,node+m+1,cmp1);
for(int i=1;i<=m;i++){
printf("%lld\n",node[i].ans);
}
return 0;
}
# include <bits/stdc++.h>
using namespace std;
const int MAXN=3e3+100;
const int mod=998244353;
int a[MAXN];
int f[MAXN][2010];
int gcd(int a,int b) { return b==0?a:gcd(b,a%b); }
int main()
{
int n; scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
f[i][a[i]]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=2000;++j){
int GCD=gcd(j,a[i]);
f[i][j]=(f[i][j]+f[i-1][j])%mod;
f[i][GCD]=(f[i][GCD]+f[i-1][j])%mod;
}
}
printf("%d",f[n][1]);
return 0;
}
# include <bits/stdc++.h>D
构造题
提供了一个思路,分奇偶讨论,分别构造,也也许构造出来的就是答案。
using namespace std;
typedef long long LL;
const int MAXN=3e3+100;
const int mod=998244353;
LL quick_pow(LL a,LL b)
{
LL ret=1;
while(b)
{
if(b&1) ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
}
int f[MAXN];
int main()
{
int n; scanf("%d",&n);
for(int i=1;i<=n;++i){
int a; scanf("%d",&a);
f[a]++; f[a]%=mod;
for(int j=1;j<=2000;++j){
(f[__gcd(a,j)]+=f[j])%=mod;
}
}
printf("%d",f[1]*quick_pow(2,mod-2)%mod);
return 0;
}
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main()
{
LL n,k; scanf("%lld%lld",&n,&k);
if(n==1){
printf("1\n2\n");
return 0;
}
if(n%2){
printf("%lld\n",n+1);
if(k==n) printf("2\n");
else printf("%lld\n",n+1);
}else{
printf("%lld\n%lld\n",n,(n+1)^1);}
return 0;
}
E DP+线段树维护区间最值 待补
写在最后面:也许打练习赛的意义在查漏补缺;也许在增强代码书写能力;现在更觉得是一种解法从
“我原来做过类似的题,解法是怎样怎样”变成“我脑海里有一种解法,是怎样怎样”一种内化为己的过
程。
    向wjmzbmr学习,acm本就是逆天而行。
 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号