A. The beautiful values of the palace
求出每个点的权值, 然后树状数组扫描线
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head
const int N = 1e6+50;
int n,m,p,cnt;
ll f[N][5],b[N];
pii pos[N][5];
int type(int x, int y) {
int a=min(abs(x-1),abs(x-n));
int b=min(abs(y-1),abs(y-n));
return min(a,b)+1;
}
ll get(int x, int y) {
int d = type(x,y);
if (d==n/2+1) return (ll)n*n;
if (x==pos[d][1].x) {
return f[d][1]+pos[d][1].y-y;
}
if (y==pos[d][2].y) {
return f[d][2]-x+pos[d][2].x;
}
if (x==pos[d][3].x) {
return f[d][3]+y-pos[d][3].y;
}
return f[d][4]+x-pos[d][4].x;
}
int solve(int x, int y) {
ll t = get(x,y);
int ret = 0;
while (t) ret+=t%10,t/=10;
return ret;
}
struct _ {
int h,w,type;
void pr() {
printf("h=%d,w=%d,type=%d\n",h,w,type);
}
};
vector<_> e[N],ee[N];
void add(int x, int y, int v, int id) {
e[x].pb({y,id,v});
}
ll ans[N];
ll cc[N];
ll query(int x) {
ll ret = 0;
for (; x; x^=x&-x) ret += cc[x];
return ret;
}
void add(int x, int v) {
for (; x<=n; x+=x&-x) cc[x]+=v;
}
void work() {
cnt = 0;
f[1][1] = 1;
f[1][2] = n;
f[1][3] = 2*n-1;
f[1][4] = 3*n-2;
pos[1][1] = pii(n,n);
pos[1][2] = pii(n,1);
pos[1][3] = pii(1,1);
pos[1][4] = pii(1,n);
int now = n-1;
REP(d,2,n/2) {
REP(j,1,4) pos[d][j]=pos[d-1][j];
--pos[d][1].x,--pos[d][1].y;
--pos[d][2].x,++pos[d][2].y;
++pos[d][3].x,++pos[d][3].y;
++pos[d][4].x,--pos[d][4].y;
f[d][1] = f[d-1][4]+now;
now -= 2;
f[d][2] = f[d][1]+now;
f[d][3] = f[d][2]+now;
f[d][4] = f[d][3]+now;
}
REP(i,0,n+1) e[i].clear(),cc[i]=0,ee[i].clear();
REP(i,1,m) {
int x, y;
scanf("%d%d", &x, &y);
ee[x].pb({y,solve(x,y),-2});
}
REP(i,1,p) {
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
--x1,--y1;
add(x2,y2,1,i);
add(x2,y1,-1,i);
add(x1,y2,-1,i);
add(x1,y1,1,i);
ans[i] =0;
}
REP(i,1,n) {
for(auto t:ee[i]) add(t.h,t.w);
for(auto t:e[i]) {
ans[t.w] += t.type*query(t.h);
}
}
REP(i,1,p) printf("%lld\n",ans[i]);
}
int main() {
int t;
scanf("%d", &t);
while (t--) scanf("%d%d%d",&n,&m,&p),work();
}
B. super_log
答案是a^a^a^...^a, 一共$b$个$a$, 可以用拓展欧拉定理
#include <iostream>
#include <algorithm>
#include <math.h>
#include <cstdio>
#include <set>
#include <map>
#include <string>
#include <vector>
#include <string.h>
#include <queue>
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define hr cout<<'\n'
#define pb push_back
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc (lc|1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false);
#define endl '\n'
using namespace std;
#define mod(a,b) a<b?a:a%b+b
typedef long long ll;
typedef pair<int,int> pii;
int P = 1e9+7;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n,ll P) {
ll r=1;
for (;n;a=mod(a*a,P),n>>=1) if(n&1)r=mod(r*a,P);
return r;
}
const int N = 1e6+10;
int f[N], n, m;
map<int,int> dp;
int phi(int x) {
if (dp.count(x)) return dp[x];
int mx = sqrt(x+0.5), r = x, t = x;
REP(i,2,mx) if (x%i==0) {
r = r/i*(i-1);
while (x%i==0) x/=i;
}
if (x>1) r=r/x*(x-1);
return dp[t]=r;
}
int query(int a, int n, int m) {
if (n==1||m==1) return mod(a,m);
return qpow(a,query(a,n-1,phi(m)),m);
}
void work() {
int a,b,m;
scanf("%d%d%d", &a, &b, &m);
if (b==0) return printf("%d\n",1%m),void();
dp.clear();
printf("%d\n",query(a,b,m)%m);
}
int main() {
int t;
scanf("%d", &t);
while (t--) work();
}
C. Tsy's number 5
设$f_i=\sum\limits_{k=1}^n[\varphi(k)=i]$, 然后原式就等于$\sum\limits_{i=1}^n\sum\limits_{j=1}^n f_if_jij2^{ij}$
可以化为求$\sum\limits_{j=1}^i jf_j 2^{ij}={\sqrt{2}}^{i^2}\sum\limits_{j=1}^ijf_j {\sqrt{2}}^{j^2-(i-j)^2}$
设$a_i = if_i{\sqrt{2}}^{i^2}$, $b_i= {\sqrt{2}}^{-i^2}$, $NTT$求一下$a*b$即可
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef int* poly;
const int P = 998244353, G = 3, Gi = 332748118, sqr = 116195171;
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
const int N = 1e6+10;
int n,phi[N],f[N];
int A[N],B[N],R[N],l,lim;
void init(int n) {
for (lim=1,l=0; lim<=n; lim<<=1,++l) ;
REP(i,0,lim-1) R[i]=(R[i>>1]>>1)|((i&1)<<(l-1));
}
void NTT(poly J, int tp=1) {
REP(i,0,lim-1) if (i<R[i]) swap(J[i],J[R[i]]);
for (int j=1; j<lim; j<<=1) {
ll T = qpow(tp==1?G:Gi,(P-1)/(j<<1));
for (int k=0; k<lim; k+=j<<1) {
ll t = 1;
for (int l=0; l<j; ++l,t=t*T%P) {
int y = t*J[k+j+l]%P;
J[k+j+l] = (J[k+l]-y)%P;
J[k+l] = (J[k+l]+y)%P;
}
}
}
if (tp==-1) {
ll inv = qpow(lim, P-2);
REP(i,0,lim-1) J[i]=(ll)inv*J[i]%P;
}
}
poly mul(poly a, poly b) {
init((n+1)*2);
REP(i,0,lim-1) A[i]=B[i]=0;
REP(i,0,n) A[i]=a[i],B[i]=b[i];
NTT(A),NTT(B);
poly c(new int[lim]);
REP(i,0,lim-1) c[i]=(ll)A[i]*B[i]%P;
NTT(c,-1);
return c;
}
void work() {
scanf("%d", &n);
REP(i,1,n) f[i] = 0;
REP(i,1,n) ++f[phi[i]];
poly a(new int[n+1]),b(new int[n+1]);
REP(i,0,n) {
a[i] = (ll)i*f[i]%P*qpow(sqr,(ll)i*i%(P-1))%P;
b[i] = qpow(sqr,P-1-(ll)i*i%(P-1));
}
poly g = mul(a,b);
int ans = 0;
REP(i,1,n) ans = (ans+(ll)i*f[i]%P*qpow(sqr,(ll)i*i%(P-1))%P*g[i])%P;
ans = ans*2%P;
REP(i,1,n) ans = (ans-(ll)i*i%P*f[i]%P*f[i]%P*qpow(2,(ll)i*i%(P-1)))%P;
if (ans<0) ans += P;
printf("%d\n", ans);
}
int main() {
REP(i,1,N-1) phi[i] = i;
REP(i,2,N-1) if (phi[i]==i) {
for (int j=i, t=i-1; j<N; j+=i) {
phi[j] = phi[j]/j*t;
}
}
int t;
scanf("%d", &t);
while (t--) work();
}
D. Robots
假设点$x$到$n$期望天数为${dp}_x$, $x$到$n$期望花费为${ans}_x$, 那么有
$${dp}_x=\frac{\sum{dp}_y+{dp}_x}{{deg}_x+1}+1$$
$${ans}_x=\frac{\sum{ans}_y+{ans}_x}{{deg}_x+1}+{dp}_x$$
第二个式子就是把费用提前计算. 因为是有向无环图, 可以建反向图, 然后拓排求出. 最终答案为${ans}_1$
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head
const int N = 1e5+10;
int n, m, deg[N], tot[N];
vector<int> g[N];
double dp[N], ans[N];
queue<int> q;
void work() {
scanf("%d%d",&n,&m);
REP(i,0,n+1) g[i].clear(), deg[i] = tot[i] = dp[i] = ans[i] = 0;
REP(i,1,m) {
int u, v;
scanf("%d%d",&u,&v);
g[v].pb(u), ++deg[u], ++tot[u];
}
q.push(n);
while (q.size()) {
int u = q.front(); q.pop();
if (u!=n) {
dp[u] = (dp[u]+1+tot[u])/tot[u];
ans[u] = (ans[u]+dp[u]+1+tot[u])/tot[u];
}
for (auto v:g[u]) {
dp[v] += dp[u];
ans[v] += ans[u]+dp[u];
if (!--deg[v]) {
q.push(v);
}
}
}
printf("%.2lf\n",ans[1]);
}
int main() {
int t;
scanf("%d", &t);
while (t--) work();
}
E. K sum
枚举$gcd$, 莫比乌斯反演一下可以得到$f_n(k)=\sum\limits_{i=1}^n i^2 \sum\limits_{d=1}^{\lfloor\frac{n}{i}\rfloor}\mu(d)\lfloor\frac{n}{id}\rfloor ^k$
比赛的时候推到这里就不会了, 这种题还是做的太少了.
然后可以枚举$id$, 就有$f_n(k)=\sum\limits_{i=1}^n\lfloor\frac{n}{i}\rfloor^k\sum\limits_{d|i}\mu(d)(\frac{i}{d})^2$
再交换一下求和次序, 就得到$\sum\limits_{i=2}^k f_n(i)=\sum\limits_{j=1}^n(\sum\limits_{i=2}^k\lfloor\frac{n}{j}\rfloor^i)(\sum\limits_{d|j}\mu(d)(\frac{j}{d})^2)$
左边是等比数列可以$O(log)$求和, 特判下公比为一的情况. 右边是$\mu * Id^2$, 可以用杜教筛求和.
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head
const int N = 1e5+10;
const int inv6 = 166666668;
const int N2 = 5e6+10;
int cnt,f[N2],p[N2],vis[N2];
map<int,int> S2;
int n, k;
char s[N];
void init() {
f[1] = 1;
REP(i,2,N2-1) {
if (!vis[i]) p[++cnt]=i,f[i] = ((ll)i*i-1)%P;
for (int j=1,t;j<=cnt&&i*p[j]<N2; ++j) {
vis[t=i*p[j]] = 1;
if (i%p[j]==0) {f[t]=(ll)f[i]*p[j]%P*p[j]%P;break;}
f[t] = (ll)f[i]*f[p[j]]%P;
}
}
REP(i,2,N2-1) f[i] = (f[i]+f[i-1])%P;
}
int g(int n) {return 1;}
int sum_g(int n) {return n;}
int sum_fg(int n) {return (ll)n*(n+1)%P*(2*n+1)%P*inv6%P;}
int sum(int n) {
if (n<N2) return f[n];
if (S2.count(n)) return S2[n];
int ans = sum_fg(n), mx = sqrt(n);
REP(i,2,mx) ans=(ans-(ll)g(i)*sum(n/i))%P;
for (int i=mx+1,j,k=n/i; i<=n; i=j+1,--k) {
j = n/k;
ans = (ans-(ll)(sum_g(j)-sum_g(i-1))*sum(k))%P;
}
return S2[n]=ans;
}
void work() {
scanf("%d%s", &n, s+1);
int len = strlen(s+1);
int k_minus = 0, k_plus = 0;
REP(i,1,len) {
k_minus = (k_minus*10ll+s[i]-'0')%P;
k_plus = (k_plus*10ll+s[i]-'0')%(P-1);
}
k_plus = (k_plus+1)%(P-1);
k_minus = (k_minus-1)%P;
int ans = 0;
for (int i=1,j; i<=n; i=j+1) {
int t = n/i;
j = n/t;
int ret;
if (t==1) ret = k_minus;
else ret = (qpow(t,k_plus)-(ll)t*t)%P*inv(t-1)%P;
ans = (ans+(ll)(sum(j)-sum(i-1))*ret)%P;
}
if (ans<0) ans += P;
printf("%d\n", ans);
}
int main() {
init();
int t;
scanf("%d", &t);
while (t--) work();
}
F. Greedy Sequence
先滑窗求出每个点后继, 然后$dp$求出每个点开头的最长路就行了.
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <queue>
#include <string>
#include <cstring>
#include <bitset>
#include <functional>
#include <random>
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define hr putchar(10)
#define pb push_back
#define lc (o<<1)
#define rc (lc|1)
#define mid ((l+r)>>1)
#define ls lc,l,mid
#define rs rc,mid+1,r
#define x first
#define y second
#define io std::ios::sync_with_stdio(false)
#define endl '\n'
#define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;})
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int P = 1e9+7, INF = 0x3f3f3f3f;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll qpow(ll a,ll n) {ll r=1%P;for (a%=P;n;a=a*a%P,n>>=1)if(n&1)r=r*a%P;return r;}
ll inv(ll x){return x<=1?1:inv(P%x)*(P-P/x)%P;}
inline int rd() {int x=0;char p=getchar();while(p<'0'||p>'9')p=getchar();while(p>='0'&&p<='9')x=x*10+p-'0',p=getchar();return x;}
//head
const int N = 1e5+10;
int n, k, a[N], nxt[N], dp[N];
int dfs(int x) {
if (dp[x]!=-1) return dp[x];
if (nxt[x]==-1) return dp[x]=1;
return dp[x]=dfs(nxt[x])+1;
}
void work() {
scanf("%d%d", &n, &k);
k = min(k, n-1);
REP(i,1,n) scanf("%d", a+i);
set<pii> s;
REP(i,1,k+1) s.insert(pii(a[i],i));
REP(i,1,n) dp[i] = nxt[i] = -1;
REP(i,1,n) {
auto t = s.lower_bound(pii(a[i],i));
if (t!=s.begin()) nxt[a[i]] = a[(--t)->y];
if (i-k>=1) s.erase(pii(a[i-k],i-k));
if (i+k+1<=n) s.insert(pii(a[i+k+1],i+k+1));
}
REP(i,1,n) printf("%d%c",dfs(i)," \n"[i==n]);
}
int main() {
int t;
scanf("%d", &t);
while (t--) work();
}