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;
}