2018 ICPC Asia Singapore Regional Conteste

A

一个环,分成k端,每段的值是所有数|起来,总值是所有端&起来。输出最大值

B

一张有自环、重边的有向图,边的耗时都为1

前k个点有生产机器,每个点j在 x*k+j 时刻产生一个产品(x>=0)

一条路在某刻只有一个产品,路口不限产品数,

问前k个点可以留下那几台机器,使满足所有产品都能被运到第n个点

C

题意

给出n个区间[ s_i , t_i ],问这些区间总覆盖数字多少个

数据范围

n<100, si,ti<365

题解

前缀和维护,然后暴力看一下那些数字有值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<bits/stdc++.h>
using namespace std;
int const maxn=400;
int qwq[maxn],sum[maxn];
int main(){
int n;
scanf("%d",&n);
int a,b;
for(int i=1;i<=n;i++){
scanf("%d%d",&a,&b);
qwq[a]+=1,qwq[b+1]-=1;
}
int ans=0;
for(int i=1;i<=365;i++){
sum[i]=sum[i-1]+qwq[i];
if(sum[i]>0)ans++;
}
printf("%d\n",ans);
return 0;
}

D

题意

给出一张无向图(可能还有多个连通块),如果1个点感染病毒,他可以感染它邻居的邻居,你可以在一些点之间加边。问最少加几条边可以使最初感染一个点后扩散到所有点都被感染。

题解

一个连通块内,如果含有一个奇环(环由奇数个点构成),就能感染整个连通块。

所以只要判断图中有几个连通块,有没有一个连通块中含有奇环。先把所有连通块联通,没有奇环的话多花1条边建立奇环。

判断奇环:暴力黑白染色

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include<bits/stdc++.h>
using namespace std;
int const maxn=5e5+10;
int tot,head[maxn],n,m,val[maxn],f[maxn],se[maxn];
bool vis[maxn];
struct edge{
int v,nxt;
}e[maxn<<1];
void build(int x,int y){
e[++tot].v=y;
e[tot].nxt=head[x];
head[x]=tot;
}
void prime(){
for(int i=1;i<=n;i++) //初始化并查集,代表元素是自己;
f[i]=i;
}

int find(int x){
if(f[x]==x)return f[x];
f[x]=find(f[x]); //查询同时路径压缩;
return f[x];
}

void merge(int x,int y){
int f1=find(x),f2=find(y);
f[f1]=f2;
}
bool you=1;
void ranse(int x){
vis[x]=1;
if(you==0)return ;
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].v;
if(vis[v]){
if(se[x]==se[v]){
you=0;return ;
}
}
else se[v]=1-se[x];
}
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].v;
if(!vis[v])ranse(v);
}
}
int main(){

scanf("%d%d",&n,&m);
prime();
tot=0;
memset(head,0,sizeof(int)*(n+5));
int a,b;
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
build(a,b);
build(b,a);
merge(a,b);
}

int ans=0;
for(int i=1;i<=n;i++){
if(find(i)==i){
ans++;
ranse(i);
}
}
printf("%d\n", ans-1+you);
return 0;
}

E

给n个点,求选3个点,最大的三角形面积。

题解

凸包+旋转卡壳

F

给定字符串s,可以改变最多k次s中的字符,如果改动后的字符串中出现连着三个或以上的相同字符,这一串字符会变为 * ,问最多让几个字符最后变为 * 。

G

题意

问某个数的非质因子有多少个

题解

预处理欧拉筛法质因子分解(记录每个数第一次被那个数筛掉),假设一个数x的m个质因子次数分别为 a1,a2....am

ans= (a1+1)*(a2+1)...(am+1)-m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

#include<bits/stdc++.h>
using namespace std;
int const maxn=2000010;
int prime[maxn],s[maxn];
int cntprime = 0;
bool flag[maxn];
void euler(){
for (int i = 2; i < maxn; i++){
if (!flag[i]) prime[++cntprime] = i;
for (int j = 1; j <= cntprime && prime[j] * i < maxn; j++){
flag[i * prime[j]] = true;
s[i*prime[j]]=prime[j];//存每个数的最小质因子
if (i % prime[j] == 0)
break;
}
}
}
int main(){
int t;
scanf("%d",&t);
int a,b;
euler();
for(int i=1;i<=t;i++){
scanf("%d",&a);
if(flag[a]==0){
printf("1\n");
continue;
}
int ans=1,cou=0,v=sqrt(a);
// for(int j=1;j<=cntprime;j++){
// if(prime[j]>v)break;

// if(a%prime[j]==0){
// // cout<<prime[j]<<endl;
// int tot=0;
// while(a%prime[j]==0){
// tot++;
// a/=prime[j];
// }
// ans*=(tot+1);
// cou++;
// }
// }一开始直接暴力求质因子,tle了
while(s[a]){//一直除最小质因子
cou++;
int tot=0,v=s[a];
while(a%v==0){
tot++;
a/=v;
}
ans*=(tot+1);
}
if(a>1){ans*=2;cou++;}
printf("%d\n",ans-cou);
}

return 0;
}

比赛:

别暴力质因数分解啊!!

H

给出初始字母s,每个字母有一个替换规则,进行k次替换。

m次询问,问替换完后某个位置的数是多少

l

在r*c的矩形中,选n次子矩形,这些子矩形都至少含有k个相同的格子。问有多少种方案,某一次选的格子不同即为一种不同方案。

J

K

L

在序列中找字典序最小的A B A B

哈哈哈

哈哈哈