A
Decription:
给出 n个数字的一个序列A,你可以将他们分为若干组,每一组的权值是里面数字的异或和,求使得所有组权值和最小。
Input
第一行给出一个n
接下来一行给出序列A
Output
输出一行包括一个整数表示最小的权值和
Sample Input:
5
1 2 6 4 3
Sample Output:
2
Data Constraint

思路:异或来异或去,其实就是不进位的加法,那么最优的解法实际上是把所有异或起来就是最优解,感性理解一下。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 100000
#define INF 100000000
#define ll long long
using namespace std;
ll qread()
{
char c=getchar();
ll x=0,pd=1;
while(c>'9'||c<'0')
{
if(c=='-') pd=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return x*pd;
}
ll n,a[N+1],len,id,ans,maxn;
int main()
{
n=qread(),len=n;
for(int i=1;i<=n;++i) a[i]=qread();
ans=a[1];
for(int i=2;i<=n;++i) ans^=a[i];
printf("%d",ans);
return 0;
}
B
Decription:
给出一个有n个正整数的序列A,m次询问,每次询问一段区间[l,r]内大小在[a,b]内的不同的数的个数。
Input
第一行给出正整数n,m
第二行给出序列A
接下来m行,每行一个询问[l,r,a,b]
Output
m行,每行对应一个询问的答案
Sample Input:
10 10
4 4 5 1 4 1 5 1 2 1
5 9 1 2
3 4 7 9
4 4 2 5
2 3 4 7
5 10 4 4
3 9 1 1
1 4 5 9
8 9 3 3
2 2 1 6
8 9 1 4
Sample Output:
2
0
0
2
1
1
1
0
1
2
Data Constraint
70%:n<=1e3,m<=1e6,l=1
100%:n<=1e5,m<=1e6,Ai<=n,l<=r,a<=b
思路:用莫队维护区间不同数的个数,用树状数组维护前缀和。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 100000
#define M 1000000
using namespace std;
int n,m,pos[N+1],v[N+1],cnt[N<<2],d[N+1],tot,tot1,ans[M+1],limit_a,limit_b,block,ll=1,rr;
struct node
{
int l,r,a,b,id;
}q[M+1];
void update1(int x)
{
for(;x<=n;x+=x&(-x)) ++cnt[x];
}
void update2(int x)
{
for(;x<=n;x+=x&(-x)) --cnt[x];
}
int sum(int x)
{
int res=0;
for(;x;x-=x&(-x)) res+=cnt[x];
return res;
}
bool cmp(node aa,node bb)
{
if(pos[aa.l]!=pos[bb.l]) return pos[aa.l]>pos[bb.l];
if(pos[aa.l]&1) return aa.r>bb.r;
return aa.r<bb.r;
}
void add(int x)
{
if(!d[v[x]]) update1(v[x]);
++d[v[x]];
}
void del(int x)
{
if(d[v[x]]==1) update2(v[x]);
--d[v[x]];
}
int qread()
{
char c=getchar();
int x=0,pd=1;
while(c>'9'||c<'0')
{
if(c=='-') pd=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=(x<<3)+(x<<1)+c-'0';
c=getchar();
}
return x*pd;
}
void ks(int x)
{
if(x>=10) ks(x/10);
putchar(x%10+'0');
}
int main()
{
n=qread(),m=qread();
block=sqrt(n);
for(int i=1;i<=n;++i) v[i]=qread(),pos[i]=(i-1)/block+1;
for(int i=1;i<=m;++i)
q[i].l=qread(),q[i].r=qread(),q[i].a=qread(),q[i].b=qread(),q[i].id=i;
sort(q+1,q+m+1,cmp);
for(int i=1;i<=m;++i)
{
while(ll<q[i].l) del(ll++);
while(ll>q[i].l) add(--ll);
while(rr<q[i].r) add(++rr);
while(rr>q[i].r) del(rr--);
ans[q[i].id]=sum(q[i].b)-sum(q[i].a-1);
}
for(int i=1;i<=m;++i) ks(ans[i]),putchar('\n');
return 0;
}
C
Decription:
T组数据,
Input
第一行给出一个整数T表示询问次数
接下来M行每行给出一个正整数N,表示该组询问中字符串的长度
Output
对于每一次询问输出一行一个整数表示答案
Sample Input:
3
1
3
6
Sample Output:
2
7
44
Data Constraint
30%:n<=1e7
100%:T<=10,n<=2e9
答案对19260817取模
思路:这个东西就是矩阵快速幂,初始化矩阵{2,4,7}然后乘一个
0 0 1
1 0 1
0 1 1
的矩阵就可以往下一项转移,考虑将矩阵快速幂取mod,然后将初始化矩阵相乘即得到答案,为最后一个。
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
#define mod 19260817
using namespace std;
ll n,t[4]={0,2,4,7},q,ans;
struct matrix
{
ll line,row,num[4][4];
matrix(ll x,ll y)
{
line=x,row=y;
memset(num,0,sizeof(num));
}
};
matrix mul(matrix a,matrix b)
{
matrix c(a.line,b.row);
for(int i=1;i<=c.line;i++)
for(int j=1;j<=c.row;j++)
for(int k=1;k<=a.row;k++)
c.num[i][j]=(c.num[i][j]+a.num[i][k]*b.num[k][j]%mod)%mod;
return c;
}
matrix ksm(matrix a,ll index)
{
matrix c(a.line,a.row);
for(int i=0;i<=3;i++) c.num[i][i]=1;
while(index)
{
if(index&1) c=mul(a,c);
index>>=1,a=mul(a,a);
}
return c;
}
int main()
{
scanf("%lld",&n);
matrix a(3,3),s(1,3),c(1,3);
s.num[1][1]=2,s.num[1][2]=4,s.num[1][3]=7;
a.num[1][3]=1,a.num[2][1]=1,a.num[2][3]=1,a.num[3][2]=1,a.num[3][3]=1;
while(n--)
{
scanf("%lld",&q);
if(q<=3)
{
printf("%lld\n",t[q]);
continue;
}
c=mul(s,ksm(a,q-3));
ans=c.num[1][3];
printf("%lld\n",ans);
}
return 0;
}

这篇博客探讨了数论问题的解决策略,利用异或性质求解序列的最优异或和。同时,介绍了如何使用莫队算法和树状数组解决区间不同数的个数查询问题。此外,还讲解了通过矩阵快速幂解决字符串计数的高效方法,并给出了相应的代码实现。

16万+

被折叠的 条评论
为什么被折叠?



