#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=151;
const int MOD1=100000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll INF=10000000010;
const ll MOD=1000000007;
typedef unsigned long long ull;
int a[4],b[4],x[4],y[4],mi;
void dfs(int z,int x,int y,int dis) {
if (dis>=mi) return ;
if (z==4) {
mi=min(mi,dis+abs(x-y));return ;
}
dfs(z+1,x,y,dis);
dfs(z+1,b[z],y,dis+abs(x-a[z])+1);
dfs(z+1,a[z],y,dis+abs(x-b[z])+1);
}
void change(int z) {
if (z==1) { a[1]=x[1];a[2]=x[2];a[3]=x[3];b[1]=y[1];b[2]=y[2];b[3]=y[3]; }
if (z==2) { a[1]=x[1];a[2]=x[3];a[3]=x[2];b[1]=y[1];b[2]=y[3];b[3]=y[2]; }
if (z==3) { a[1]=x[2];a[2]=x[1];a[3]=x[3];b[1]=y[2];b[2]=y[1];b[3]=y[3]; }
if (z==4) { a[1]=x[2];a[2]=x[3];a[3]=x[1];b[1]=y[2];b[2]=y[3];b[3]=y[1]; }
if (z==5) { a[1]=x[3];a[2]=x[1];a[3]=x[2];b[1]=y[3];b[2]=y[1];b[3]=y[2]; }
if (z==6) { a[1]=x[3];a[2]=x[2];a[3]=x[1];b[1]=y[3];b[2]=y[2];b[3]=y[1]; }
}
int main()
{
int i,j,t,n,m,e,f;
ll ans;
scanf("%d", &t);
while (t--) {
ans=0;
scanf("%d%d", &n, &m);
scanf("%d%d%d%d%d%d", &x[1], &y[1], &x[2], &y[2], &x[3], &y[3]);
for (i=1;i<=m;i++) {
scanf("%d%d", &e, &f);
mi=1000000000;
for (j=1;j<7;j++) {
change(j);dfs(1,e,f,0);
}
ans=(ans+(ll)mi*i)%MOD;
}
printf("%I64d\n", (ans+MOD)%MOD);
}
return 0;
}
C:给定n个数a[i]。m组询问,每次询问s,t:s最少要通过多少次操作变成t。有两种操作:(1)将x的二进制的某一位取反。(2)将x与一个给定的a[i]异或。
分析:首先我们分析下这两种操作,初一看异或和取反不好操作,但是仔细一看会发现我们可以将第一种操作变成第二种操作:将x的第i位取反相当于与(1<<(i-1))异或。那么我们就变成了(s^x1^x2...^xk=t)==>(x1^x2^...^xk=s^t),我们发现所有数的范围在10^5以内,并且能用来异或的数xi最多只有35个,那么我们先bfs对所有的1~10^5都处理出最小所需的操作数,然后对于每一次询问直接给出答案即可。O(10^5)
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=500010;
const int MAX=151;
const int MOD1=1000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
const ll INF=10000000010;
typedef unsigned long long ull;
int a[40],q[N],dp[N];
queue<int>Q;
int main()
{
int i,t,n,m,x,y,w;
ll ans;
scanf("%d", &t);
while (t--) {
ans=0;
scanf("%d%d", &n, &m);
for (i=1;i<=n;i++) scanf("%d", &a[i]);
for (i=1;i<=20;i++) a[n+i]=1<<(i-1);
while (!Q.empty()) Q.empty();
memset(q,0,sizeof(q));
Q.push(0);q[0]=1;dp[0]=0;n+=20;
while (!Q.empty()) {
w=Q.front();Q.pop();
for (i=1;i<=n;i++)
if (w^a[i]<=100000&&a[i]<=100000) {
if (q[w^a[i]]) continue ;
q[w^a[i]]=1;
dp[w^a[i]]=dp[w]+1;
Q.push(w^a[i]);
}
}
for (i=1;i<=m;i++) {
scanf("%d%d", &x, &y);
ans=(ans+(ll)dp[x^y]*i)%MOD;
}
printf("%I64d\n", (ans+MOD)%MOD);
}
return 0;
}
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=151;
const int MOD1=100000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll INF=10000000010;
const ll MOD=1000000007;
typedef unsigned long long ull;
int tot,u[N],v[2*N],pre[2*N];
void add(int a,int b) {
v[tot]=b;pre[tot]=u[a];u[a]=tot++;
}
int d[N],q[N],vis[N];
priority_queue<int, vector<int>, greater<int> >Q;
int main()
{
int a,b,i,g,t,n,m,k,w;
ll ans;
scanf("%d", &t);
while (t--) {
scanf("%d%d%d", &n, &m, &k);
memset(d,0,sizeof(d));
tot=0;memset(u,-1,sizeof(u));
for (i=1;i<=m;i++) {
scanf("%d%d", &a, &b);add(a,b);d[b]++;
}
while (!Q.empty()) Q.pop();
ans=0;g=1;
memset(q,0,sizeof(q));
memset(vis,0,sizeof(vis));
for (i=1;i<=n;i++)
if (d[i]<=k) { Q.push(i);q[i]=1; }
while (!Q.empty()) {
w=Q.top();Q.pop();q[w]=0;
if (d[w]<=k&&!vis[w]) {
ans=(ans+(ll)w*g)%MOD;
vis[w]=1;g++;k-=d[w];
printf("%d xx\n", w);
for (i=u[w];i!=-1;i=pre[i]) {
d[v[i]]--;
if (vis[v[i]]) continue ;
if (d[v[i]]<=k&&!q[v[i]]) Q.push(v[i]);
}
}
}
printf("%I64d\n", (ans+MOD)%MOD);
}
return 0;
}
线段树:
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=100010;
const int MAX=151;
const int MOD1=100000007;
const int MOD2=100000009;
const int INF=100000010;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=1000000007;
typedef unsigned long long ull;
int tot,u[N],v[2*N],pre[2*N];
void add(int a,int b) {
v[tot]=b;pre[tot]=u[a];u[a]=tot++;
}
int d[N],t[4*N];
void build_tree(int a,int l,int r) {
if (l+1==r) {
t[a]=d[l];return ;
}
int mid=(l+r)/2;
build_tree(a<<1,l,mid);
build_tree((a<<1)+1,mid,r);
t[a]=min(t[a<<1],t[(a<<1)+1]);
}
int query(int a,int l,int r,int k) {
if (l+1==r) return l;
int mid=(l+r)/2;
if (t[a<<1]<=k) return query(a<<1,l,mid,k);
else return query((a<<1)+1,mid,r,k);
}
void change(int a,int l,int r,int w) {
if (l+1==r) {
t[a]=d[w];return ;
}
int mid=(l+r)/2;
if (w<mid) change(a<<1,l,mid,w);
else change((a<<1)+1,mid,r,w);
t[a]=min(t[a<<1],t[(a<<1)+1]);
}
int main()
{
int a,b,i,j,t,n,m,k,w;
ll ans;
scanf("%d", &t);
while (t--) {
scanf("%d%d%d", &n, &m, &k);
tot=0;ans=0;
memset(d,0,sizeof(d));
memset(u,-1,sizeof(u));
for (i=1;i<=m;i++) {
scanf("%d%d", &a, &b);add(a,b);d[b]++;
}
build_tree(1,1,n+1);
for (i=1;i<=n;i++) {
w=query(1,1,n+1,k);
k-=d[w];ans=(ans+(ll)i*w)%MOD;
d[w]=INF;change(1,1,n+1,w);
for (j=u[w];j!=-1;j=pre[j]) {
d[v[j]]--;change(1,1,n+1,v[j]);
}
}
printf("%I64d\n", (ans+MOD)%MOD);
}
return 0;
}