2019 ICPC Asia-East Continent Final
题目
A. City
https://codeforces.com/gym/102471/problem/A
(
n
+
1
)
×
(
m
+
1
)
(n+1)\times (m+1)
(n+1)×(m+1) 个格点,求有多少组格点对
(
a
,
b
)
(a,b)
(a,b) ,其中
a
a
a 和
b
b
b 的中点也是格点,
(
a
,
b
)
(a,b)
(a,b) 和
(
b
,
a
)
(b,a)
(b,a) 视为同一对,
1
≤
n
,
m
≤
1000
1\le n,m\le 1000
1≤n,m≤1000
条件是横纵坐标差均为偶数
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=100010,M=1000010,P=1e9+7;
const int inf=0x3f3f3f3f;
const int INF=0xcfcfcfcf;
const db eps=1e-9,pi=2*asin(1);
template<typename tn> void read(tn &n);
template<typename tn1,typename tn2> bool cmax(tn1 &x,tn2 y) { return x<y?x=y,true:false; }
template<typename tn1,typename tn2> bool cmin(tn1 &x,tn2 y) { return x>y?x=y,true:false; }
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
int ADD(int x,int y,int p=P) { return x+y>=p?x+y-p:x+y; }
int MINUS(int x,int y,int p=P) { return x-y<0?x-y+p:x-y; }
#define plus(a,b) a=ADD(a,b)
#define minus(a,b) a=MINUS(a,b)
#define mul(a,b) a=1ll*(a)*(b)%P
#define mem(a,b) memset(a,b,sizeof(a))
template<typename tn> void read(tn &n)
{
tn s=0,flag=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=-1;
for(;'0'<=ch&&ch<='9';ch=getchar()) s=s*10+ch-'0';
if(ch=='.')
{
ch=getchar();
tn r=0,R=1;
for(;'0'<=ch&&ch<='9';ch=getchar()) r=r*10+ch-'0',R*=10;
s+=r/R;
}
n=s*flag;
}
int main()
{
int n,m; read(n),read(m);
ll ans=-(n+1)*(m+1);
for(int i=1;i<=n+1;i++) for(int j=1;j<=m+1;j++)
ans+=1ll*((n+1-i)/2+1)*((m+1-j)/2+1)+1ll*((m+1-j)/2)*((i-1)/2);
printf("%lld\n",ans);
return 0;
}
C. Dirichlet k k k-th root
https://codeforces.com/gym/102471/problem/C
g
=
f
k
g=f^k
g=fk ,已知
g
g
g ,求
f
f
f ,其中
f
k
f^k
fk 为
f
f
f 的
k
k
k 次迪利克雷卷积,
n
≤
100000
n\le 100000
n≤100000
(3h左右写出来几乎可以过的代码,但zz的写错了迪利克雷卷积,导致直到快要结束了才过。。。)
(以下所有推导均建立在“通过”的基础上)
∵
g
=
f
k
∴
f
=
g
1
k
∴
f
≡
g
k
−
1
m
o
d
p
(
m
o
d
p
)
(
最
后
一
步
其
实
不
知
道
是
怎
么
来
的
,
最
后
过
样
例
就
直
接
交
了
)
\begin{aligned}&\because g=f^k\\&\therefore f=g^{\frac{1}{k}}\\ &\therefore f\equiv g^{k^{-1}\mod p}\pmod p\\&(最后一步其实不知道是怎么来的,最后过样例就直接交了)\end{aligned}
∵g=fk∴f=gk1∴f≡gk−1modp(modp)(最后一步其实不知道是怎么来的,最后过样例就直接交了)
求出
k
k
k 在模
p
p
p 意义下的逆元,然后做迪利克雷卷积快速幂即可,复杂度
Θ
(
n
log
2
n
)
\Theta(n\log^2n)
Θ(nlog2n) (vp的时候zz的写了个
Θ
(
n
n
log
n
)
\Theta(n\sqrt n\log n)
Θ(nnlogn) ,好歹卡过去了(966ms))
代码
Θ
(
n
n
log
n
)
\Theta(n\sqrt n\log n)
Θ(nnlogn) (准确来说那个
n
\sqrt n
n 应该是因子个数):
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=100010,M=1000010,P=998244353;
const int inf=0x3f3f3f3f;
const int INF=0xcfcfcfcf;
const db eps=1e-9,pi=2*asin(1);
template<typename tn> void read(tn &n);
template<typename tn1,typename tn2> bool cmax(tn1 &x,tn2 y) { return x<y?x=y,true:false; }
template<typename tn1,typename tn2> bool cmin(tn1 &x,tn2 y) { return x>y?x=y,true:false; }
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
int ADD(int x,int y,int p=P) { return x+y>=p?x+y-p:x+y; }
int MINUS(int x,int y,int p=P) { return x-y<0?x-y+p:x-y; }
#define plus(a,b) a=ADD(a,b)
#define minus(a,b) a=MINUS(a,b)
#define mul(a,b) a=1ll*(a)*(b)%P
#define mem(a,b) memset(a,b,sizeof(a))
int n,k,nik;
int g[N],res[N];
int quickmi(int x,int n)
{
int res=1;
for(;n;n>>=1)
{
if(n&1) res=1ll*res*x%P;
x=1ll*x*x%P;
}
return res;
}
#define ni(x) quickmi(x,P-2)
vector<int> fac[N];
void init(int n=100000)
{
for(int i=1;i<=n;i++)
for(int j=1;j*j<=i;j++)
if(i%j==0) fac[i].push_back(j);
}
void quickmi(int *f,int m)
{
res[1]=1;
for(int i=2;i<=n;i++) res[i]=0;
for(;m;m>>=1)
{
if(m&1)
{
int h[N];
for(int i=1;i<=n;i++) h[i]=0;
for(int i=1;i<=n;i++)
{
for(int k=0,sz=fac[i].size();k<sz;k++)
{
int j=fac[i][k];
h[i]=(h[i]+1ll*res[j]*f[i/j])%P;
if(j*j!=i) h[i]=(h[i]+1ll*f[j]*res[i/j])%P;
}
}
for(int i=1;i<=n;i++) res[i]=h[i];
}
int h[N];
for(int i=1;i<=n;i++) h[i]=0;
for(int i=1;i<=n;i++)
{
for(int k=0,sz=fac[i].size();k<sz;k++)
{
int j=fac[i][k];
h[i]=(h[i]+1ll*f[j]*f[i/j])%P;
if(j*j!=i) h[i]=(h[i]+1ll*f[j]*f[i/j])%P;
}
}
for(int i=1;i<=n;i++) f[i]=h[i];
}
for(int i=1;i<=n;i++) f[i]=res[i];
}
template<typename tn> void read(tn &n)
{
tn s=0,flag=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=-1;
for(;'0'<=ch&&ch<='9';ch=getchar()) s=s*10+ch-'0';
if(ch=='.')
{
ch=getchar();
tn r=0,R=1;
for(;'0'<=ch&&ch<='9';ch=getchar()) r=r*10+ch-'0',R*=10;
s+=r/R;
}
n=s*flag;
}
int main()
{
init();
read(n),read(k),nik=ni(k);
for(int i=1;i<=n;i++) read(g[i]);
quickmi(g,nik);
for(int i=1;i<=n;i++) printf("%d ",res[i]);
putchar('\n');
return 0;
}
Θ ( n log 2 n ) \Theta(n\log^2n) Θ(nlog2n) :
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=100010,M=1000010,P=998244353;
const int inf=0x3f3f3f3f;
const int INF=0xcfcfcfcf;
const db eps=1e-9,pi=2*asin(1);
template<typename tn> void read(tn &n);
template<typename tn1,typename tn2> bool cmax(tn1 &x,tn2 y) { return x<y?x=y,true:false; }
template<typename tn1,typename tn2> bool cmin(tn1 &x,tn2 y) { return x>y?x=y,true:false; }
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
int ADD(int x,int y,int p=P) { return x+y>=p?x+y-p:x+y; }
int MINUS(int x,int y,int p=P) { return x-y<0?x-y+p:x-y; }
#define plus(a,b) a=ADD(a,b)
#define minus(a,b) a=MINUS(a,b)
#define mul(a,b) a=1ll*(a)*(b)%P
#define mem(a,b) memset(a,b,sizeof(a))
int n,k,nik;
int g[N],res[N];
int quickmi(int x,int n)
{
int res=1;
for(;n;n>>=1)
{
if(n&1) res=1ll*res*x%P;
x=1ll*x*x%P;
}
return res;
}
#define ni(x) quickmi(x,P-2)
void quickmi(int *f,int m)
{
res[1]=1;
for(int i=2;i<=n;i++) res[i]=0;
for(;m;m>>=1)
{
if(m&1)
{
int h[N];
for(int i=1;i<=n;i++) h[i]=0;
for(int i=1;i<=n;i++)
for(int j=1;i*j<=n;j++)
h[i*j]=(h[i*j]+1ll*res[i]*f[j])%P;
for(int i=1;i<=n;i++) res[i]=h[i];
}
int h[N];
for(int i=1;i<=n;i++) h[i]=0;
for(int i=1;i<=n;i++)
for(int j=1;i*j<=n;j++)
h[i*j]=(h[i*j]+1ll*f[i]*f[j])%P;
for(int i=1;i<=n;i++) f[i]=h[i];
}
}
template<typename tn> void read(tn &n)
{
tn s=0,flag=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=-1;
for(;'0'<=ch&&ch<='9';ch=getchar()) s=s*10+ch-'0';
if(ch=='.')
{
ch=getchar();
tn r=0,R=1;
for(;'0'<=ch&&ch<='9';ch=getchar()) r=r*10+ch-'0',R*=10;
s+=r/R;
}
n=s*flag;
}
int main()
{
read(n),read(k),nik=ni(k);
for(int i=1;i<=n;i++) read(g[i]);
quickmi(g,nik);
for(int i=1;i<=n;i++) printf("%d ",res[i]);
putchar('\n');
return 0;
}
D. Fire
https://codeforces.com/gym/102471/problem/D
(队友zz了7发)
队友代码:
#include<bits/stdc++.h>
#define N 100005
#define BUFF must_ac
using namespace std;
bool cur1;
int n,m;
long long a[N];
int head[N],id;
struct edge{
int to,nxt;
}E[N<<1];
inline void add_edge(int a,int b){
E[++id]=(edge){b,head[a]};
head[a]=id;
}
inline void Rd(int &res){
char c;res=0;
while(c=getchar(),c<48);
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>47);
return;
}
long long dp1[N],dp2[N],mn[N];
long long sze[N];
int que[N],cnt;
inline bool cmp1(int a,int b){
return dp1[a]+2*sze[a]<dp1[b]+2*sze[b];
}
void dfs(int x,int f){
sze[x]=1;
dp1[x]=2e9;
dp2[x]=-1;
for(int i=head[x];i;i=E[i].nxt){
int v=E[i].to;
if(v==f)continue;
dfs(v,x);
sze[x]+=sze[v];
}
cnt=0;
for(int i=head[x];i;i=E[i].nxt){
int v=E[i].to;
if(v==f)continue;
que[++cnt]=v;
}
sort(que+1,que+cnt+1,cmp1);
long long h=2;
for(int i=1;i<=cnt;i++){
int v=que[i];
dp1[x]=min(dp1[x],mn[i]=(dp1[v]-h+1));
h+=sze[v]*2;
}
h=2;
mn[cnt+1]=2e9;
for(int i=cnt-1;i>=1;i--)mn[i]=min(mn[i],mn[i+1]);
long long last=2e9;
for(int i=1;i<=cnt;i++){
int v=que[i];
dp2[x]=max(dp2[x],min(a[x]+m-2*(sze[x]-sze[v]),min(last,min(dp2[v]-2*(sze[x]-sze[v])+1,mn[i+1]+2*sze[v]))));
// if(x==1)printf("!!%d\n",dp2[v]-2*(sze[x]-sze[v])+1);
// if(x==1)printf("!!%d\n",v);
last=min(last,dp1[v]-h+1);
// if(x==1)printf("!!%lld\n",last);
h+=sze[v]*2;
}
dp1[x]=min(dp1[x],min(a[x],a[x]+m-2*sze[x]));
if(!cnt)dp2[x]=a[x];
else dp2[x]=min(dp2[x],a[x]);
// printf("!!%d %lld %lld\n",x,dp1[x],dp2[x]);
}
bool cur2;
int main(){
// printf("%lf MB\n",(&cur2-&cur1)/1024.0/1024);
// freopen("data.txt","r",stdin);
Rd(n);Rd(m);
for(int i=1,a,b;i<n;i++){
Rd(a);Rd(b);
add_edge(a,b);
add_edge(b,a);
}
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
dfs(1,0);
if(dp2[1]<0)puts("-1");
else printf("%lld\n",dp2[1]);
return 0;
}
E. Flow
https://codeforces.com/gym/102471/problem/E
G
G
G 是一个
<
n
,
m
>
<n,m>
<n,m> 图,每条边长度为
1
1
1 ,有流量。从
1
1
1 到
n
n
n 有若干条长度相等的不相交路径,每次操作可以将
1
1
1 条边流量
−
1
-1
−1 ,将另一条边流量
+
1
+1
+1 ,求最少进行多少次操作可以使
1
1
1 到
n
n
n 的最大流最大,
n
≤
100000
,
m
≤
200000
n\le 100000,\;m\le 200000
n≤100000,m≤200000
显然最大流可以简单求出。考虑把所有边的流量都拆分成若干条流量为
1
1
1 的边,这样一条路径只与路径上初始流量为
1
1
1 的边数有关。简单贪心填满初始为
1
1
1 的边多的路径即可
队友代码:
#include <set>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 200005;
struct node {
ll x, k;
node(){}
node(int _x) { x = _x; }
node(int _x, int _k) { x = _x, k = _k; }
bool operator < (const node &o) const {
return x < o.x;
}
} nd;
node P[MAXN<<1]; int tot;
struct edge {
int v, w;
edge(){}
edge(int _v, int _w) {
v = _v, w = _w;
}
} e[MAXN];
int N, M;
vector<edge> beg;
vector<int> vec;
set<node> S;
set<node>::iterator it;
ll L;
/*ll cal(ll x, ll k, ll res)
{
ll a = 0;
while (k) {
while (k && res< L-x) res += x, k--;
if (k && res>=L-x) res -= L-x, a += L-x, k--;
}
return a;
}*/
int main()
{
scanf("%d%d", &N, &M);
for (int i=1; i<=M; i++) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
if (u==1) beg.push_back(edge(v, w));
else e[u] = edge(v, w);
}
for (auto b:beg) {
int v = b.v;
vec.clear(), vec.push_back(b.w);
while (v!=N) vec.push_back(e[v].w), v = e[v].v;
sort(vec.begin(), vec.end());
L = vec.size();
for (int i=1; i< L; i++) {
int k = vec[i] - vec[i-1], x = L - i;
if (x==0) continue;
if ((it=S.find(node(x)))!=S.end()) {
nd = (*it), S.erase(it);
nd.k += k;
S.insert(nd);
} else S.insert(node(x, k));
}
}
// printf("L = %d\n", L);
ll sum = 0, ans = 0;
for (auto v:S) P[++tot] = v, sum += v.k * v.x; //printf("(%d, %d)\n", v.x, v.k);
ll line = sum / L;
for (int i=tot; i>=1; i--) {
if (line> P[i].k) ans += (L-P[i].x)*P[i].k, line -= P[i].k;
else {
ans += (L-P[i].x) * line;
break;
}
}
printf("%lld\n", ans);
}
H. King
https://codeforces.com/gym/102471/problem/H
给定一个长为
n
n
n 的序列
b
b
b 和质数
p
p
p,求最长的子序列
a
a
a 的长度
m
m
m,满足
∀
i
∈
[
2
,
m
]
,
a
i
≡
q
a
i
−
1
(
m
o
d
p
)
\forall i\in[2,m],\;a_i\equiv qa_{i-1}\pmod p
∀i∈[2,m],ai≡qai−1(modp) ,若
m
<
n
2
m<\frac{n}{2}
m<2n 则输出
−
1
-1
−1 。多测,
n
≤
200000
n\le 200000
n≤200000
xjb乱搞
(非正解)观察可得有所选中的数中一半以上在
b
b
b 中距离不超过
2
2
2 ,那么可以将
b
b
b 中所有距离为
1
1
1 和
2
2
2 的数的比值取出来,将其中出现次数
≥
n
4
−
1
\ge\frac{n}{4}-1
≥4n−1 的都试一遍,这样的数不会太多(雾)。
已知
q
q
q 求最长的
a
a
a 可以通过
d
p
dp
dp 实现。
前一部分时间复杂度
Θ
(
能过
)
\Theta(\text{能过})
Θ(能过) ,后一部分时间复杂度
Θ
(
n
log
n
)
\Theta(n\log n)
Θ(nlogn)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=200010,M=1000010;
int P;
const int inf=0x3f3f3f3f;
const int INF=0xcfcfcfcf;
const db eps=1e-9,pi=2*asin(1);
template<typename tn> void read(tn &n);
template<typename tn1,typename tn2> bool cmax(tn1 &x,tn2 y) { return x<y?x=y,true:false; }
template<typename tn1,typename tn2> bool cmin(tn1 &x,tn2 y) { return x>y?x=y,true:false; }
#define mp(x,y) make_pair(x,y)
#define pii pair<int,int>
#define pil pair<int,ll>
#define pli pair<ll,int>
#define pll pair<ll,ll>
int ADD(int x,int y,int p=P) { return x+y>=p?x+y-p:x+y; }
int MINUS(int x,int y,int p=P) { return x-y<0?x-y+p:x-y; }
#define plus(a,b) a=ADD(a,b)
#define minus(a,b) a=MINUS(a,b)
#define mul(a,b) a=1ll*(a)*(b)%P
#define mem(a,b) memset(a,b,sizeof(a))
int quickmi(int x,int n)
{
int res=1;
for(;n;n>>=1)
{
if(n&1) res=1ll*res*x%P;
x=1ll*x*x%P;
}
return res;
}
#define ni(x) quickmi(x,P-2)
int n;
int b[N];
int sum[2*N],rk[2*N],tot=0;
map<int,int> id;
map<int,int> dp;
int ans[N];
struct aa {
int sum,rk;
} a[2*N];
bool operator<(const aa &a,const aa &b)
{
return a.sum>b.sum;
}
template<typename tn> void read(tn &n)
{
tn s=0,flag=1;
char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') flag=-1;
for(;'0'<=ch&&ch<='9';ch=getchar()) s=s*10+ch-'0';
if(ch=='.')
{
ch=getchar();
tn r=0,R=1;
for(;'0'<=ch&&ch<='9';ch=getchar()) r=r*10+ch-'0',R*=10;
s+=r/R;
}
n=s*flag;
}
int main()
{
int T; read(T);
while(T--)
{
tot=0;
id.clear();
read(n),read(P);
for(int i=1;i<=n;i++) read(b[i]);
for(int i=1;i<n;i++)
{
int q=1ll*b[i+1]*ni(b[i])%P;
if(id.find(q)==id.end()) tot++,id[q]=tot,rk[tot]=q,sum[tot]=0;
sum[id[q]]++;
}
for(int i=1;i<n-1;i++)
{
int q=1ll*b[i+2]*ni(b[i])%P;
if(id.find(q)==id.end()) tot++,id[q]=tot,rk[tot]=q,sum[tot]=0;
sum[id[q]]++;
}
for(int i=1;i<=tot;i++) a[i].sum=sum[i],a[i].rk=rk[i];
sort(a+1,a+tot+1);
int ANS=0;
for(int k=1;k<=tot;k++)
{
if(a[k].sum<n/4-1) break;
dp.clear();
int q=a[k].rk;
for(int i=1;i<=n;i++)
{
if(dp.find(b[i])!=dp.end()) ans[i]=dp[b[i]]+1;
else ans[i]=1;
int p=1ll*b[i]*q%P;
if(ans[i]>dp[p]) dp[p]=ans[i];
cmax(ANS,ans[i]);
}
}
if(ANS*2>=n) printf("%d\n",ANS);
else printf("-1\n");
}
return 0;
}
M. Value
https://codeforces.com/gym/102471/problem/M
一个集合
A
⊂
[
1
,
n
]
A\subset[1,n]
A⊂[1,n] 的价值是
∑
i
∈
A
a
i
−
∑
i
∈
A
,
j
∈
A
b
j
⋅
[
∃
k
>
1
,
i
k
=
j
]
\sum_{i\in A} a_i-\sum_{i\in A,\;j\in A}b_j\cdot[\exist k>1,\;i^k=j]
∑i∈Aai−∑i∈A,j∈Abj⋅[∃k>1,ik=j] ,求最大的价值,
n
≤
100000
n\le 100000
n≤100000
注意到
[
1
,
n
]
[1,n]
[1,n] 可以被划分为若干个组,其中组内可能满足
i
k
=
j
i^k=j
ik=j ,组间一定不满足
i
k
=
j
i^k=j
ik=j ,每个组的大小不超过
17
17
17 ,因此可以
2
m
2^m
2m 枚举选或不选 ,应该可以过吧
队友代码:
#include<bits/stdc++.h>
#define N 100005
#define BUFF must_ac
using namespace std;
bool cur1;
int n;
int a[N],b[N];
bool mark[N],hv[N];
long long ans;
long long que[233];
int cnt;
inline void Rd(int &res){
char c;res=0;
while(c=getchar(),c<48);
do res=(res<<3)+(res<<1)+(c^48);
while(c=getchar(),c>47);
return;
}
inline bool check(long long x,long long y){
long long res=y;
while(res<x)res*=y;
return res==x;
}
bool cur2;
int main(){
// printf("%lf MB\n",(&cur2-&cur1)/1024.0/1024);
// freopen("data.txt","r",stdin);
Rd(n);
for(int i=1;i<=n;i++)Rd(a[i]);
for(int i=1;i<=n;i++)Rd(b[i]);
ans=a[1];
for(int i=2;i<=n;i++)if(!mark[i]){
long long last=i;
for(int j=2;;j++){
last*=i;
if(last<=n)mark[last]=1,mark[i]=1;
else break;
}
}
for(int i=2;i<=n;i++)if(!mark[i])ans+=a[i];
for(int i=2;i<=n;i++)if(mark[i]&&!hv[i]){
que[cnt=1]=i;
for(;;cnt++){
hv[que[cnt]]=1;
que[cnt+1]=que[cnt]*i;
if(que[cnt+1]>n)break;
}
long long mx=0;
for(int j=1;j<(1<<cnt);j++){
long long h=0;
for(int k=1;k<=cnt;k++)if(j&(1<<(k-1)))h+=a[que[k]];
for(int k=2;k<=cnt;k++)if(j&(1<<(k-1))){
for(int l=1;l<k;l++)if(j&(1<<(l-1))){
if(check(que[k],que[l]))h-=b[que[k]];
}
}
mx=max(mx,h);
}
ans+=mx;
}
printf("%lld\n",ans);
return 0;
}