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