版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/oidoidoid/article/details/87948892
D
题意是对于一个序列,有一些询问,询问一个区间里出现了偶数次的数字的异或和。
离线回答,应用线段树即可
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<set>
#include<math.h>
#include<queue>
#include<map>
#include<stack>
#include<deque>
#define go(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
#define ll long long
#define N 1000005
using namespace std;
struct query{
int l,r,i,ans;
}q[N];
struct node{
int x,i,p;
}a[N];
int t[4*N],n,m,x[N],cnt=0,has[N];
map<int,int>mp;
bool cmp1(query a, query b){ return a.r<b.r; }
bool cmp2(query a, query b){ return a.i<b.i; }
bool cmp3(node a, node b){ return a.x<b.x; }
bool cmp4(node a, node b){ return a.i<b.i; }
void init(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",&a[i].x);
a[i].i=i;
x[i]=x[i-1]^a[i].x; //xor 前缀和
}
sort(a+1,a+1+n,cmp3);
for (int i=1;i<=n;i++){
if (a[i].x==a[i-1].x) a[i].p=cnt;
else a[i].p=++cnt;
}
sort(a+1,a+1+n,cmp4);
scanf("%d",&m);
for(int i=1;i<=m;++i){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].i=i;
}
}
void updata(int k){
t[k]=t[k*2]^t[k*2+1];
}
void insert(int k, int l, int r, int x,int c){
if (l>x||r<x) return;
if (x==r&&x==l){
t[k]=c;
return;
}
int m=(l+r)/2;
insert(k*2,l,m,x,c);insert(k*2+1,m+1,r,x,c);
updata(k);
}
int query(int k, int l, int r, int left, int right){
if (l>right||r<left) return 0;
if (left<=l&&r<=right){
return t[k];
}
int m=(l+r)/2;
return query(k*2,l,m,left,right)^query(k*2+1,m+1,r,left,right);
}
void solve(){
sort(q+1,q+m+1,cmp1);
memset(has,-1,sizeof(has));
int r=0;
for (int i=1;i<=m;i++){
while (r<q[i].r){
r++;
if (has[a[r].p]!=-1){
insert(1,1,n,has[a[r].p],0);
}
has[a[r].p]=r;
insert(1,1,n,r,a[r].x);
}
q[i].ans=query(1,1,n,q[i].l,q[i].r)^x[q[i].r]^x[q[i].l-1];
}
sort(q+1,q+1+m,cmp2);
for (int i=1;i<=m;i++){
printf("%d\n",q[i].ans);
}
}
int main(){
init();
solve();
}
E
题意是:对于一个数字,给出一个序列,求一个最短的子序列使得这个子序列的积是这个数字的倍数
如果有很多个这样的子序列输出和最小的那个
做法:预处理k的约数,然后离散化进行dp就可以了(约数并没有那么多)
输出方案这个地方wa了好几次,然后又忘记特判1……
#include<iostream>
#include<map>
#include<algorithm>
#include<string.h>
#include<math.h>
#define ll long long
using namespace std;
ll num[10005],a[1005], ai[1005];
int dp[2][10005],p[1005][10005];
ll sum[2][10005];
int tot=0;
map<ll, int> mp;
ll gcd(ll a, ll b) {
return b==0?a:gcd(b,a%b);
}
void init(ll k){
for (ll i=1;i<=sqrt((double)k+0.5);i++){
if (k%i==0){
num[++tot]=i;
if (i*i!=k) num[++tot]=k/i;
}
}
sort(num+1,num+1+tot);
//cout<<tot<<endl;
for(int i=1;i<=tot;i++) mp[num[i]]=i;
}
int main(){
ll n,k;
cin>>n>>k;
init(k);
ll minn,tag;
for (int i=1;i<=n;i++){
cin>>a[i];
ai[i]=gcd(a[i],k);
if (i==1) minn=a[i],tag=1;
else{
if (minn>a[i]) minn=a[i],tag=i;
}
}
if (k==1){
cout<<1<<endl<<tag<<endl;
return 0;
}
memset(dp,0x3f,sizeof(dp));
memset(sum,0x3f,sizeof(sum));
memset(p,0,sizeof(p));
dp[0][1]=0;
for (int i=1;i<=n;i++){
for (int j=1;j<=tot;j++){ //第j个约数
int now=i%2;
int tmp=gcd(ai[i],num[j]); //最大贡献多少
int x=mp[num[j]/tmp];
dp[now][j]=dp[1-now][j];
sum[now][j]=sum[1-now][j];
p[i][j]=j;
if (dp[1-now][x]+1<dp[now][j]){
dp[now][j]=dp[1-now][x]+1;
sum[now][j]=sum[1-now][x]+a[i];
p[i][j]=x;
}
else if (dp[1-now][x]+1==dp[now][j]&&
sum[1-now][x]+a[i]<sum[now][j]){
sum[now][j]=sum[1-now][x]+a[i];
p[i][j]=x;
}
}
}
if (dp[n%2][tot]==1061109567) cout<<"-1"<<endl;
else {
cout<<dp[n%2][tot]<<endl;
int tmp=tot, j=n;
for (int i=1;i<=dp[n%2][tot];i++){
for (;j>=1;j--){
if (p[j][tmp]!=tmp){
cout<<j<<" ";
tmp=p[j][tmp];
j--;
break;
}
}
}
}
return 0;
}