「EC Final 2019」狄利克雷 k 次根
题意:给出一个函数的前项,求它在狄利克雷卷积意义下的次根的前项,这里的狄利克雷卷积是指。
做法:
容易发现,也就是狄利克雷卷积的单位元。
所以求出的逆元后即可直接
狄利克雷卷积快速幂即可。
#include<bits/stdc++.h>
#define maxn 1000005
#define mod 998244353
using namespace std;
int n,K,a[maxn],b[maxn];
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod; return r; }
void mul(int *a,int *b,int *c){
static int d[maxn];
for(int i=1;i<=n;i++) d[i] = 0;
for(int i=1;i<=n;i++) for(int j=1,k=i;k<=n;k+=i,j++)
d[k] = (d[k] + 1ll * a[i] * b[j]) % mod;
for(int i=1;i<=n;i++) c[i] = d[i];
}
int main(){
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
b[1] = 1;K = Pow(K , mod-2);
for(;K;K>>=1,mul(a,a,a)) if(K&1) mul(a,b,b);
for(int i=1;i<=n;i++) printf("%d%c",b[i]," \n"[i==n]);
}
考虑狄利克雷生成函数
狄利克雷卷积就是他们的生成函数相乘。
对于的生成函数求再再即可。
有
其中是一个与无关的常数,是因为对于常数显然,所以需要一个来补全。
但是这个题它的常数是,这就很为难了,你不能不说它是常数,但是他的确看上去和有关。
就这样吧,
同时可以得到
因为不存在项所以可以递推出。
最大的问题是如何处理。
需要重新定义导数和,而积分和则分别是他们的逆运算。
新的定义是一种线性变换满足链式法则()
对于需要满足,所以需要满足,
对于此题令为的质因子个数,即可。
#include<bits/stdc++.h>
#define maxn 1000005
#define mod 998244353
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
using namespace std;
int n,K,a[maxn],b[maxn];
int pr[maxn],vis[maxn],sg[maxn],cnt_pr;
int inv[maxn];
void ln(int *a){
static int b[maxn];
rep(i,1,n) b[i] = 1ll * a[i] * sg[i] % mod;
rep(i,1,n){
for(int j=2,k=2*i;k<=n;k+=i,j++)
b[k] = (b[k] - 1ll * b[i] * a[j]) % mod;
b[i] = 1ll * b[i] * inv[sg[i]] % mod;
}
rep(i,1,n) a[i] = b[i];
}
void exp(int *a){
static int b[maxn];
rep(i,1,n) b[i] = 1ll * a[i] * sg[i] % mod , a[i] = 0;
a[1] = 1;
rep(i,1,n){
if(i>1) a[i] = 1ll * a[i] * inv[sg[i]] % mod;
for(int j=2,k=2*i;k<=n;k+=i,j++)
a[k] = (a[k] + 1ll * a[i] * b[j]) % mod;
}
}
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod;return r; }
int main(){
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
inv[0] = inv[1] = 1;
rep(i,2,n){
if(!vis[i]) pr[cnt_pr++] = i , sg[i] = 1;
for(int j=0;pr[j] * i <= n;j++){
vis[i * pr[j]] = 1;
sg[i * pr[j]] = sg[i] + 1;
if(i % pr[j] == 0) break;
}
}
rep(i,2,20) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;
ln(a);K = Pow(K , mod-2);
rep(i,1,n) a[i] = 1ll * a[i] * K % mod;
exp(a);
rep(i,1,n) printf("%d%c",a[i]," \n"[i==n]);
}
2018 ACM-ICPC World Finals H .Single Cut of Failure
给出一个的矩形,并给出若干条端点在矩形边上且不和矩形的边重合的线段,给出最少用几条端点在矩形边上的线段可以切割所有线段的方案。
发现每条线段都会被主对角线和副对角线之一切割,所以答案最多是。
将第条线段的两个端点都标号为,对于所有端点极角排序后求是否有一个长度为的连续子序列中没有相同标号的点即可。
#include<bits/stdc++.h>
#define maxn 2000006
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define db double
using namespace std;
int n,w,h;
int c[maxn],cnt[maxn],A[maxn],B[maxn];
db ang[maxn];
bool cmp(const int &u,const int &v){ return ang[u] < ang[v]; }
int main(){
scanf("%d%d%d",&n,&w,&h);
rep(i,1,n){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
::c[i*2-1] = i*2-1 , ::c[i*2] = i*2;
ang[i*2-1] = atan2(b-h/2.0,a-w/2.0);
A[i*2-1] = a , B[i*2-1] = b;
ang[i*2] = atan2(d-h/2.0,c-w/2.0);
A[i*2] = c , B[i*2] = d;
}
sort(c+1,c+1+2*n,cmp);
c[0] = c[2*n] , c[2*n+1] = c[1];
int j=1;
rep(i,1,2*n){
for(;cnt[(c[i]+1)/2] == 1;)
cnt[(c[j++]+1)/2] = 0;
cnt[(c[i]+1)/2] = 1;
if(i - j + 1 == n){
printf("%d\n",1);
if(A[c[i]] == w) printf("%lf %lf ",(db)A[c[i]],B[c[i]]+0.5);
else if(B[c[i]] == h) printf("%lf %lf ",A[c[i]]-0.5,(db)B[c[i]]);
else if(A[c[i]] == 0) printf("%lf %lf ",(db)A[c[i]],B[c[i]]-0.5);
else printf("%lf %lf ",A[c[i]]+0.5,(db)B[c[i]]);
i = j-1;
if(A[c[i]] == w) printf("%lf %lf\n",(db)A[c[i]],B[c[i]]+0.5);
else if(B[c[i]] == h) printf("%lf %lf\n",A[c[i]]-0.5,(db)B[c[i]]);
else if(A[c[i]] == 0) printf("%lf %lf\n",(db)A[c[i]],B[c[i]]-0.5);
else printf("%lf %lf\n",A[c[i]]+0.5,(db)B[c[i]]);
return 0;
}
}
printf("%d\n",2);
printf("0.5 0 %lf %lf\n",w-0.5,(db)h);
printf("%lf %lf %lf %lf\n",0.5,(db)h,w-0.5,0.0);
}
2018 ACM-ICPC World Finals I. Triangles
给出一个图,数等边三角形个数。
维护往左,往左上,往右上的最长能走多远,
然后对于每一排横着扫,用BIT在处,移动到处,其中是往右上能走的最长距离,以此求出以为右下角的三角形个数。
注意还需要处理以为左上角的三角形个数。
#include<bits/stdc++.h>
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
#define pb push_back
using namespace std;
int r,c;
char s[6005][12005];
int U[6005][12005],D[6005][12005];
int tr[24005];
vector<int>G[24005];
void upd(int u,int v){ for(;u<=4*c;u+=u&-u) tr[u] += v; }
int qry(int u){ int r=0;for(;u;u-=u&-u) r+=tr[u];return r; }
int main(){
scanf("%d%d\n",&r,&c);
rep(i,1,2*r-1)
fgets(s[i]+1,2*c+2,stdin);
LL ans = 0;
queue<int>q;
for(int i=1;i<=2*r-1;i+=2){
for(int j=(i/2&1?3:1);j<=2*c-1;j+=4){
if(s[i][j-1] == ' '){
for(;!q.empty();q.pop()){
int x = q.front();
if(x + D[i][x] >= j)
upd(2 * c - x , -1) , G[x+D[i][x]].clear();
}
}
if(s[i-1][j-1] != ' ' && s[i-1][j-1])
U[i][j] = U[i-2][j-2] + 1;
else
U[i][j] = 0;
if(s[i-1][j+1] != ' ' && s[i-1][j+1])
D[i][j] = D[i-2][j+2] + 4;
else
D[i][j] = 0;
ans += qry(2*c-(j-4*U[i][j]));
q.push(j);
upd(2*c-j,1);
G[j+D[i][j]].pb(j);
for(;!G[j].empty();)
upd(2*c-G[j].back(),-1),G[j].pop_back();
}
for(;!q.empty();q.pop()){
int x = q.front();
if(x + D[i][x] > 2*c-1)
upd(2 * c - x , -1) , G[x+D[i][x]].clear();
}
}
for(int i=2*r-1;i>=1;i-=2){
for(int j=(i/2&1?3:1);j<=2*c-1;j+=4){
if(s[i][j-1] == ' '){
for(;!q.empty();q.pop()){
int x = q.front();
if(x + D[i][x] >= j)
upd(2 * c - x , -1) , G[x+D[i][x]].clear();
}
}
if(s[i+1][j-1] != ' ' && s[i+1][j-1])
U[i][j] = U[i+2][j-2] + 1;
else
U[i][j] = 0;
if(s[i+1][j+1] != ' ' && s[i+1][j+1])
D[i][j] = D[i+2][j+2] + 4;
else
D[i][j] = 0;
ans += qry(2*c-(j-4*U[i][j]));
q.push(j);
upd(2*c-j,1);
G[j+D[i][j]].pb(j);
for(;!G[j].empty();)
upd(2*c-G[j].back(),-1),G[j].pop_back();
}
for(;!q.empty();q.pop()){
int x = q.front();
if(x + D[i][x] > 2*c-1)
upd(2 * c - x , -1) , G[x+D[i][x]].clear();
}
}
printf("%lld\n",ans);
}