首先对于每个 ( x , y ) (x,y) (x,y),我们可以 O ( 1 ) O(1) O(1)的查询出这个坐标的值。接下来就将问题转化为了一个 1 0 6 ⋅ 1 0 6 10^6 \cdot 10^6 106⋅106的矩阵,每次查询子矩阵内的点的和。
考虑将所有的 y y y离散化,计 m p i , j mp_{i,j} mpi,j表示 ( 1 , 1 ) − ( i , j ) (1,1)-(i,j) (1,1)−(i,j)的和,那么对于 ( x 1 , y 1 ) − > ( x 2 , y 2 ) (x_1,y_1)->(x_2,y_2) (x1,y1)−>(x2,y2),答案即为
m p x 2 , y 2 − m p x 1 − 1 , y 2 − m p x 2 , y 1 − 1 + m p x 1 − 1 , y 1 − 1 mp_{x_2,y_2}-mp_{x_1-1,y_2}-mp_{x_2,y1-1}+mp_{x_1-1,y_1-1} mpx2,y2−mpx1−1,y2−mpx2,y1−1+mpx1−1,y1−1
考虑离线做法:
把所有的点按照 x x x从小到达排序,每加入一个点,利用树状数组插入,每次查询,利用树状数组查询四个前缀和即可。时间复杂度 ( m + 4 p ) ⋅ l o g ( m + 4 p ) (m+4p) \cdot log(m+4p) (m+4p)⋅log(m+4p)。
#include
using namespace std;
const int N = 1e6+100;
const int mod = 1e9+7;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll llINF = 0x3f3f3f3f3f3f3f3f;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fep(i,a,b) for(int i=(a);i>=(b);i--)
inline bool read(ll &num) {
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
return true;
}
ll T,n,p,m,c[N];
int lowbit(ll x){
return (x&(-x));
}
void add(ll x,ll v){
for(;x<N;x+=lowbit(x)){
c[x]+=v;
//cout<
}
}
ll query(ll x){
ll ans=0;
for(;x;x-=lowbit(x)){
ans+=c[x];
}
return ans;
}
//BIT
struct point{
ll x,y;
int flag;
}pp[600000];
bool cmp(point a,point b){
if(a.x==b.x){
if(a.y==b.y){
return a.flag<b.flag;
}
return a.y<b.y;
}
return a.x<b.x;
}
ll dig(ll x){
ll ans=0;
while(x){
ans+=x%10;
x/=10;
}
return ans;
}
ll cal(ll x,ll y){//计算(x,y)处的值
x=x-n/2-1;
y=y-n/2-1;
ll t=max(abs(x),abs(y));
if(x>=y) return n*n-4*t*t-2*t-x-y;
else return n*n-4*t*t+2*t+x+y;
}
map<pair<ll,ll>,ll> mmp;
ll yy[N],id[N];
ll x__1[100001],y__1[100001],x__2[100001],y__2[100001];
int main(){
read(T);
while(T--){
mmp.clear();
read(n);read(m);read(p);
memset(c,0,sizeof(c));
ll x,y,x_1,y_1,x_2,y_2;
rep(i,1,m){
read(x);read(y);
pp[i]={x,y,0};
}
rep(i,1,p){
read(x_1);read(y_1);read(x_2);read(y_2);
x__1[i]=x_1;y__1[i]=y_1;x__2[i]=x_2;y__2[i]=y_2;
pp[++m]={x_1-1,y_1-1,1};
pp[++m]={x_2,y_2,1};
pp[++m]={x_1-1,y_2,1};
pp[++m]={x_2,y_1-1,1};
}
rep(i,1,m) yy[i]=pp[i].y;
sort(yy+1,yy+m+1);
int siz=unique(yy+1,yy+m+1)-yy-1;
sort(pp+1,pp+m+1,cmp);
rep(i,1,m){
id[i]=lower_bound(yy+1,yy+siz+1,pp[i].y)-yy;
}
//离散化
rep(i,1,m){
if(pp[i].flag==0){
add(id[i],dig(cal(pp[i].x,pp[i].y)));
//cout<
}
else{
mmp[{pp[i].x,pp[i].y}]=query(id[i]);
//cout<
}
}
rep(i,1,p){
//cout<
printf("%lld\n",mmp[{x__2[i],y__2[i]}]-mmp[{x__1[i]-1,y__2[i]}]-mmp[{x__2[i],y__1[i]-1}]+mmp[{x__1[i]-1,y__1[i]-1}]);
}
}
return 0;
}
计算 a a a a . . . % m a^{a^{a^{a...}}} \% m aaaa...%m,总共有 b b b个 a a a。
直接递归欧拉降幂即可。
降幂公式:
a b % p = { a b % ϕ ( p ) % p g c d ( a , p ) = 1 a b % p g c d ( a , p ) ≠ 1 , b < ϕ ( p ) a b % ϕ ( p ) + ϕ ( p ) % p g c d ( a , p ) ≠ 1 , ϕ ( p ) ≤ b a^b \% p= \begin{cases} a^{b \% \phi(p)} \%p & gcd(a,p)=1\\ a^b \% p & gcd(a,p) \neq1 ,b < \phi(p)\\ a^{b \% \phi(p)+\phi(p)} \% p & gcd(a,p)\neq 1, \phi(p) \leq b \end{cases} ab%p=⎩⎪⎨⎪⎧ab%ϕ(p)%pab%pab%ϕ(p)+ϕ(p)%pgcd(a,p)=1gcd(a,p)̸=1,b<ϕ(p)gcd(a,p)̸=1,ϕ(p)≤b
#include
using namespace std;
const int N = 2e6+100;
const int mod = 1e9+7;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll llINF = 0x3f3f3f3f3f3f3f3f;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fep(i,a,b) for(int i=(a);i>=(b);i--)
inline bool read(ll &num) {
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
return true;
}
ll ph[N];
void init(){
rep(i,1,N-10){
ph[i]=i;
}
rep(i,2,N-10){
if(ph[i]==i){
for(int j=i;j<=N-10;j+=i){
ph[j]=ph[j]/i*(i-1);
}
}
}
}
ll qpow(ll a,ll b,ll mod){
ll ans=1;
while(b){
if(b&1) ans=(ans%mod*a%mod)%mod;
a=(a%mod*a%mod)%mod;
b>>=1;
}
return ans%mod;
}
bool check(ll a,ll b,ll m){
if(b==0) return 1>=ph[m];
if(b==1) return a>=ph[m];
ll ans=1;
if(ans>=ph[m]) return 1;
rep(i,1,b-1){
rep(j,1,a){
ans*=a;
if(ans>=ph[m]) return 1;
}
}
return 0;
}
ll solve(ll a,ll b,ll m){
if(m==1) return 0;
if(b==0) return 1%m;
if(b==1) return a%m;
if(__gcd(a,m)==1){
return qpow(a,solve(a,b-1,ph[m]),m);
}
else{
if(check(a,b-1,m)){
return qpow(a,solve(a,b-1,ph[m])+ph[m],m);
}
else return qpow(a,solve(a,b-1,m),m);
}
}
ll T,a,b,m;
int main(){
//freopen("1.in", "r", stdin);
read(T);
init();
//cout<
while(T--){
read(a);read(b);read(m);
printf("%lld\n",solve(a,b,m)%m);
}
return 0;
}
一个有向图,机器人从 u u u可以不接着往下走,也可以随便选一个邻接点走下去,所有的情况都是等概率的,一天只能执行一次上面的操作。第 i i i天执行任意操作的的花费为 i i i,计算从 1 1 1到 n n n的期望花费。
计 d a y u day_{u} dayu为从 u u u到 n n n的期望天数, c o s t u cost_{u} costu代表 u u u到 n n n的期望花费。
那么有:
d a y u = ( d a y u + 1 ) ⋅ 1 d u + 1 + ∑ ( d a y v + 1 ) ⋅ 1 d u + 1 day_{u}=(day_{u}+1) \cdot \frac{1}{d_{u}+1}+\sum{(day_{v}+1)\cdot \frac{1}{d_{u}+1}} dayu=(dayu+1)⋅du+11+∑(dayv+1)⋅du+11
那么我们就可以得到花费期望的转移:
c o s t u = ( c o s t u + d a y u + 1 ) ⋅ 1 d u + 1 + ∑ ( c o s t v + d a y v + 1 ) ⋅ 1 d u + 1 cost_{u}=(cost_{u}+day_{u}+1) \cdot \frac{1}{d_{u}+1}+ \sum{(cost_{v}+day_{v}+1)\cdot \frac{1}{d_{u}+1}} costu=(costu+dayu+1)⋅du+11+∑(costv+dayv+1)⋅du+11
移项后DFS转移即可。
#include
using namespace std;
const int N = 1e6+100;
const int mod = 1e9+7;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll llINF = 0x3f3f3f3f3f3f3f3f;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fep(i,a,b) for(int i=(a);i>=(b);i--)
inline bool read(ll &num) {
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
return true;
}
int T,n,m,u,v;
double day[N],cost[N],d[N];
bool vis[N];
vector<int> G[N];
double dfsa(int u){
if(day[u]) return day[u];
if(u==n) return day[u];
double x=0;
for(int v:G[u]){
dfsa(v);
x+=(day[v]+1)/(d[u]+1);
}
x+=1.0/(d[u]+1);
return day[u]=x*(d[u]+1)/(d[u]);
}
double dfsb(int u){
if(cost[u]) return cost[u];
if(u==n) return cost[u];
double y=0;
for(int v:G[u]){
dfsb(v);
y+=(cost[v]+day[v]+1)/(d[u]+1);
}
y+=(day[u]+1)/(d[u]+1);
return cost[u]=(y*(d[u]+1))/(d[u]);
}
int main(){
//freopen("1.in", "r", stdin);
scanf("%d",&T);
while(T--){
scanf("%d %d",&n,&m);
rep(i,1,n){
d[i]=0,G[i].clear();
day[i]=cost[i]=0;
}
rep(i,1,m){
scanf("%d %d",&u,&v);
G[u].push_back(v);
d[u]+=1.0;
}
dfsa(1);
printf("%.2lf\n",dfsb(1));
}
return 0;
}
会发现每个点的前驱都是唯一的,我们用主席树求出对于每个点的左右 k k k远的区间内最大的小于这个数字的数,然后 O ( n ) O(n) O(n)的递推即可。
#include
using namespace std;
const int maxn = 1e5+100;
typedef long long ll;
struct node
{
ll sum,l,r;
}t[maxn*32];
int cnt;
void update(ll l,ll r,ll &x,ll y,ll pos){
t[++cnt]=t[y];t[cnt].sum++;x=cnt;//复制节点并且更新
if(l==r) return ;
int mid=(l+r)>>1;
if(mid>=pos) update(l,mid,t[x].l,t[y].l,pos);
else update(mid+1,r,t[x].r,t[y].r,pos);
}
int query(int a,int b,int x,int l,int r)
{
if(l==r)
{
if(l==x)
return 0;
else
return l;
}
int mid=(l+r)>>1;
int xx=t[t[b].l].sum-t[t[a].l].sum;
int yy=t[t[b].r].sum-t[t[a].r].sum;
int res=0;
if(yy&&x>mid)
res=query(t[a].r,t[b].r,x,mid+1,r);
if(xx&&!res)
res=query(t[a].l,t[b].l,x,l,mid);
return res;
}
int a[maxn],pos[maxn],ans[maxn];
ll roots[maxn];
int main(){
//freopen("1.in","r",stdin);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int T;
cin>>T;
while(T--){
cnt=0;
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];pos[a[i]]=i;
}
for(int i=1;i<=n;i++) update(1,n,roots[i],roots[i-1],a[i]);
for(int i=1;i<=n;i++){
int L=max(pos[i]-k,1);
int R=min(pos[i]+k,n);
int now=query(roots[L-1],roots[R],i,1,n);
if(now==0) ans[i]=1;
else ans[i]=ans[now]+1;
}
for(int i=1;i<=n-1;i++) cout<<ans[i]<<' ';
cout<<ans[n]<<endl;
}
return 0;
}
跑6次 S P F A SPFA SPFA即可。
#include
using namespace std;
const int mod = 1e9+7;
typedef long long ll;
const int N = 401;
const int INF = 0x3f3f3f3f;
const ll llINF = 0x3f3f3f3f3f3f3f3f;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fep(i,a,b) for(int i=(a);i>=(b);i--)
inline bool read(ll &num) {
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
return true;
}
ll dis[N];
int s,t,n,m,u,v;
ll w;
vector<pair<int,ll> > G[N];
bool vis[N];
void SPFA(int s)//若存在负环返回false
{
queue<int> q;
memset(vis,0,sizeof(vis));
rep(i,0,n) dis[i]=llINF;
dis[s]=0;
q.push(s);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=0;
for(auto V:G[u]){
int v=V.first;ll w=V.second;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
if(!vis[v]){
q.push(v);
vis[v]=1;
}
}
}
}
return ;
}
int main(){
//freopen("1.in", "r", stdin);
int T;
scanf("%d",&T);
while(T--){
rep(i,0,n) G[i].clear();
scanf("%d %d",&n,&m);
rep(i,1,m){
scanf("%d %d %lld",&u,&v,&w);
G[u].push_back({v,w});
}
rep(i,1,6){
scanf("%d %d",&s,&t);
SPFA(t);
printf("%lld\n",-dis[s]);
G[s].push_back({t,-dis[s]});
}
}
return 0;
}