6605 Yukikaze and Demons
exgcd+点分治
点分治统计路径,exgcd求出
x
∗
1
0
l
e
n
+
n
u
m
≡
0
(
m
o
d
k
)
x*10^{len}+num \equiv 0 (mod\ k)
x∗10len+num≡0(mod k)
数组
O
(
1
)
O(1)
O(1)查询即可
复杂度问题在于x的个数,因为
1
0
l
e
n
10^{len}
10len固定个人感觉是没办法卡的
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;
const int M=5e5+5;
int n,m;
int node_num;
int best_;
int f[M];
int size[M];
int bin[M];
int sta[M];
char s[M];
int e_size,head[M];
s64 ans;
bool vis[M];
struct edge{
int v,nxt;
}e[M*2];
void e_add(int u,int v) {
e[++e_size]=(edge){v,head[u]};
head[u]=e_size;
}
int exgcd(int&x,int&y,int a,int b) {
if(!b) return x=1,y=0,a;
int gcd=exgcd(x,y,b,a%b);
int t=x;
x=y;
y=t-a/b*y;
return gcd;
}
void dp(int x,int fa) {
f[x]=0;
size[x]=1;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(v==fa||vis[v]) continue;
dp(v,x);
size[x]+=size[v];
f[x]=max(f[x],size[v]);
}
f[x]=max(f[x],node_num-size[x]);
if(!best_||f[best_]>f[x]) best_=x;
}
void add_(int x,int fa,int k,int sum,int t,int ha) {
sum=(sum+1ll*k*s[x]%m)%m;
sta[sum]+=t;
if(ha) ans+= sum==0;
//cout<<x<<" "<<sum<<endl;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(vis[v]||v==fa) continue;
add_(v,x,10ll*k%m,sum,t,ha);
}
}
void calc_(int x,int fa,int dep,int sum) {
sum=(sum+s[x])%m;
size[x]=1;
//hardest
int xx,yy;
int x_,y_;
int gcd=exgcd(xx,yy,bin[dep],-m);
if(sum%gcd==0) {
xx=-sum/gcd*xx;
yy=-sum/gcd*yy;
if(gcd<0) gcd=-gcd;
x_=m/gcd,y_=bin[dep]/gcd;
//cout<<"-_-"<<x<<" "<<xx<<" "<<yy<<" "<<bin[dep]<<" "<<-m<<" "<<gcd<<endl;
//cout<<x_<<" "<<bin[dep]<<endl;
if(xx<0) {
int c=(-xx-1)/x_+1;
xx+=c*x_,yy+=c*y_;
}
if(xx>0) {
int c=xx/x_;
xx-=c*x_,yy-=c*y_;
}
if(yy<0) {
int c=(-yy-1)/y_+1;
xx+=c*x_,yy+=c*y_;
}
while (xx<m) {
//cout<<"-_-"<<x<<" "<<xx<<" "<<sta[xx]<<endl;
ans+=sta[xx],xx+=x_;
}
}
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(vis[v]||v==fa) continue;
calc_(v,x,dep+1,10*sum%m);
size[x]+=size[v];
}
}
void solve(int x) {
//cout<<"-_-"<<x<<endl;
++sta[s[x]];
ans+= s[x]==0;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(vis[v]) continue;
add_(v,x,10,s[x],1,1);
}
//cout<<"-_-"<<endl;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(vis[v]) continue;
add_(v,x,10,s[x],-1,0);
calc_(v,x,1,0);
add_(v,x,10,s[x],1,0);
//cout<<"-_-"<<x<<" "<<v<<" "<<ans<<endl;
}
// while(1);
--sta[s[x]];
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(vis[v]) continue;
add_(v,x,10,s[x],-1,0);
}
//cout<<x<<" "<<ans<<endl;
vis[x]=1;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(vis[v]) continue;
node_num=size[v];
best_=0;
dp(v,x);
solve(best_);
}
}
void divid_() {
best_=0;
node_num=n;
dp(1,0);
solve(best_);
}
int main() {
//freopen("a.txt","r",stdin);
//freopen("a.out","w",stdout);
int test_;
cin>>test_;
while (test_--) {
scanf("%d%d%s",&n,&m,s+1);
rep(i,1,n) s[i]-='0',s[i]%=m;
rep(i,2,n) {
int x,y;
scanf("%d%d",&x,&y);
e_add(x,y),e_add(y,x);
}
bin[0]=1;
rep(i,1,n) bin[i]=10*bin[i-1]%m;
divid_();
printf("%lld\n",ans);
ans=0;
e_size=0;
rep(i,1,n) vis[i]=head[i]=0;
}
}
6608 Fansblog
素数之间间距不会很大,暴力枚举判断即可
(
p
r
i
m
e
−
1
)
!
≡
1
(
m
o
d
p
r
i
m
e
)
(prime-1)! \equiv 1 (mod\ prime)
(prime−1)!≡1(mod prime)
除掉暴力枚举的不是素数的数即可
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
typedef long long s64;
const int M=1e7+5;
s64 mod;
int prime[M];
bool not_prime[M];
bool check(s64 x) {
for(int i=1;i<=prime[0] && 1ll*i*i<=x;++i)
if(x%prime[i]==0) return 0;
return 1;
}
s64 mul(s64 a,s64 b,s64 mod) {
s64 ans=a*b-(s64)((long double)a/mod*b+0.5)*mod;
return ans<0?ans+mod:ans;
}
s64 qmul(s64 a,s64 k,s64 mod) {
s64 ans=1;
for(;k;k>>=1,a=mul(a,a,mod)) if(k&1) ans=mul(a,ans,mod);
return ans;
}
int main() {
//freopen("a.txt","r",stdin);
//freopen("a.out","w",stdout);
rep(i,2,10000000) {
if(!not_prime[i]) prime[++prime[0]]=i;
rep(j,1,prime[0]) {
if(i*prime[j]>10000000) break;
not_prime[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
int test_;
cin>>test_;
while (test_--) {
cin>>mod;
s64 x=mod-1,ans=mod-1;
while (!check(ans)) {
x=mul(x,qmul(ans,mod-2,mod),mod);
--ans;
}
cout<<x<<endl;
}
}
6611 K Subsequence
费用流
优化建图
a
i
≤
a
j
≤
a
k
a_{i} \leq a_{j} \leq a_{k}
ai≤aj≤ak只建边
(
i
,
k
)
(i,k)
(i,k)
这样会错,再加上
(
i
,
i
′
,
f
l
o
w
=
m
,
c
o
s
t
=
0
)
(i,i',flow=m,cost=0)
(i,i′,flow=m,cost=0)即可
注意pre[S]要清空
只有一组数据不清空是可以的,因为pre[S]从来都是0
但是多组数据pre[S]会被上一组修改
就TLE了
感觉oi和acm还真的是不太一样啊
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
const int M=5e3+5;
int n,m;
int a[M];
int S,SS,T;
int e_size,head[M];
bool inq_[M];
int dis[M],pre[M];
struct edge{
int u,v,w,c,nxt;
}e[M*100];
void e_add(int u,int v,int w,int c) {
e[++e_size]=(edge){u,v,w,c,head[u]};
head[u]=e_size;
}
void insert(int u,int v,int w,int c) {
e_add(u,v,w,c),e_add(v,u,0,-c);
}
void spfa() {
memset(dis,-0x3f,sizeof(dis));
queue <int> q;
dis[S]=0;
q.push(S);
pre[S]=0;
while (!q.empty()) {
int r=q.front();
q.pop();
inq_[r]=0;
for(int i=head[r];i;i=e[i].nxt) {
int v=e[i].v;
if(dis[v]<dis[r]+e[i].c&&e[i].w) {
pre[v]=i;
dis[v]=dis[r]+e[i].c;
if(!inq_[v]) inq_[v]=1,q.push(v);
}
}
}
}
void feiyong() {
int ans=0;
while (spfa(),dis[T]>0) {
int t=1e9;
for(int i=pre[T];i;i=pre[e[i].u]) t=min(t,e[i].w);
ans+=t*dis[T];
for(int i=pre[T];i;i=pre[e[i].u]) e[i].w-=t,e[i^1].w+=t;
}
printf("%d\n",ans);
}
int main() {
//freopen("a.txt","r",stdin);
int test_;
cin>>test_;
while (test_--) {
scanf("%d%d",&n,&m);
rep(i,1,n) scanf("%d",a+i);
e_size=1;
memset(head,0,sizeof(head));
S=2*n+5,SS=S+1,T=SS+1;
insert(S,SS,m,0);
rep(i,1,n) insert(SS,i,m,0),insert(i,i+n,1,a[i]),insert(i,i+n,m,0),insert(i+n,T,m,0);
rep(i,1,n) {
int pre=2e5;
rep(j,i+1,n) if(a[i]<=a[j]&&pre>a[j]) {
pre=a[j];
insert(i+n,j,m,0);
}
}
feiyong();
}
}
6613 Squrirrel
直接树形dp
f
[
i
]
[
0
/
1
]
f[i][0/1]
f[i][0/1]代表i的子树中是否使用边时最大深度最小的情况
同理
g
[
i
]
[
0
/
1
]
g[i][0/1]
g[i][0/1]是除掉i的子树…
线性dp即可
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,l,r) for(int i=l;i>=r;--i)
using namespace std;
const int M=2e5+5;
int n;
int e_size,head[M];
int fa[M];
int f[M][2],g[M][2];
int ans[M];
struct edge {
int v,w,nxt;
}e[M*2];
void e_add(int u,int v,int w) {
e[++e_size]=(edge) {v,w,head[u]};
head[u]=e_size;
}
void dp1(int x) {
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(v==fa[x]) continue;
fa[v]=x;
dp1(v);
}
f[x][0]=f[x][1]=0;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(v==fa[x]) continue;
f[x][1]=min( min( max(f[x][1],f[v][0]+e[i].w) , max(f[x][0],f[v][1]+e[i].w) ) , max(f[x][0],f[v][0]) );
f[x][0]=max(f[x][0],f[v][0]+e[i].w);
}
//cout<<"-_-"<<x<<" "<<f[x][0]<<" "<<f[x][1]<<endl;
}
void dp2(int x) {
if(fa[x]) {
g[x][0]=g[x][1]=0;
g[x][0]=g[fa[x]][0];
g[x][1]=g[fa[x]][1];
int sum=0;
for(int i=head[fa[x]];i;i=e[i].nxt) {
int v=e[i].v;
if(v==x) sum=e[i].w;
if(v==fa[fa[x]]||v==x) continue;
g[x][1]=min( min( max(g[x][1],f[v][0]+e[i].w) , max(g[x][0],f[v][1]+e[i].w) ) , max(g[x][0],f[v][0]) );
g[x][0]=max(g[x][0],f[v][0]+e[i].w);
}
g[x][1]=min(g[x][1]+sum,g[x][0]);
g[x][0]+=sum;
}
//cout<<x<<" "<<g[x][0]<<" "<<g[x][1]<<endl;
for(int i=head[x];i;i=e[i].nxt) {
int v=e[i].v;
if(v==fa[x]) continue;
dp2(v);
}
}
int main() {
//freopen("a.txt","r",stdin);
int test_;
cin>>test_;
while (test_--) {
scanf("%d",&n);
rep(i,2,n) {
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
e_add(x,y,z),e_add(y,x,z);
}
dp1(1);
dp2(1);
rep(i,1,n) f[i][1]=min(f[i][1],f[i][0]),g[i][1]=min(g[i][1],g[i][0]);
rep(i,1,n) ans[i]=min( max(f[i][1],g[i][0]) , max(g[i][1],f[i][0]) );
int p=1;
rep(i,2,n) if(ans[i]<ans[p]) p=i;
printf("%d %d\n",p,ans[p]);
//rep(i,1,n) printf("%d ",ans[i]);
//puts("");
e_size=0;rep(i,1,n) head[i]=0;
}
}