2017ccpc秦皇岛

2017ccpc秦皇岛

zoj 3981(A)

题目要求

第一行三个数字n, m, q表示有m个座位围成一个环,n个队伍,q次A题
接下来n个数表示n个队伍所在位置(1<=ai<=m)
再接下来q行,每行a, b表示第a个队伍在第b秒A了一道题
有一个只会每一秒顺时针移动一个位置的发气球机器人
只要当前队伍有题目已经A了就会给他对应数量的气球(当然每道题最多1个气球)
如果a队伍在b时刻A了一道题,并在c时刻才拿到气球,那么这个队伍就会积累c-b点不开心值
求一个机器人起始位置(一开始是第0秒)使得所有队伍最终不开心值之和最小

参考AC代码

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
#include<bits/stdc++.h>
#define maxn 100050
#define LL long long
using namespace std;
int T,n,m,q;
LL s[maxn],t[maxn];
int main(){
// freopen("input.txt","r",stdin);
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++) scanf("%lld",&s[i]);
LL sum=0,ans=1e18;
for(int i=1;i<=q;i++){
LL a,b;
scanf("%lld%lld",&a,&b);
t[i]=(s[a]-1-b+m)%m;
sum+=t[i];
}
sort(t+1,t+1+q);
for(int i=1;i<=q;i++){
ans=min(ans,sum+(LL)m*(i-1)-t[i]*q);
}
printf("%lld\n",ans);
}
return 0;
}

思路

假设机器人位置在1位置上 对于每个a b 那么每次产生的不开心值就是s[a]-1-b 如果是负值 +m mod m
把所有的不开心值加起来 就是初始的sum 然后对t排序
枚举每一道题作为起点时候的情况
对于第i道题目,因为位置往后走,后面的题目的时间就会减少t[i],前面的题目的时间就会增加m-t[i]
因此递推式是sum-(q-i)×t[i]+i×(m-t[i])=sum+m×(i-1)-t[i]×p
注意LL

zoj 3983(C)

题目要求

给出由字符g a o组成的9个字符串 每个字符各出现3次
每次可以删除任意连续的相同字符 如果删除的字母为3个 ans++
问最优删除后获得的最大的ans是多少

参考AC代码

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
#include<bits/stdc++.h>
#define fi first
#define se second
using namespace std;
int t,ans;
string s;
void dfs(string str,int cnt){
vector<pair<int,int> >re;
int len=str.length();
if(len==0){
ans=max(ans,cnt);
return;
}
int cur=0;
for(int i=0;i<len;i++){
if(str[i]!=str[cur]){
re.push_back(make_pair(cur,i));
cur=i;
}
}
re.push_back(make_pair(cur,len));
for(auto p:re){
string temp=str;
temp.erase(temp.begin()+p.fi,temp.begin()+p.se);
if(p.se-p.fi==3) dfs(temp,cnt+1);
else dfs(temp,cnt);
}
}
int main(){
// freopen("input.txt","r",stdin);
scanf("%d",&t);
while(t--){
cin>>s;
ans=0;
dfs(s,0);
cout<<ans<<endl;
}
return 0;
}

思路

dfs暴搜
re记录每个字符串连续字符的起始和终止位置
暴力删除每个位置 如果删除长度为3 cnt++

zoj 3987(G)

参考AC代码

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
import java.util.*;
import java.math.*;
public class Main{
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
BigInteger x0 = BigInteger.valueOf(0);
BigInteger x1 = BigInteger.valueOf(1);
BigInteger x2 = BigInteger.valueOf(2);
BigInteger []b = new BigInteger[5005];
b[0]=x1;
for(int i=1;i<5000;i++)
b[i]=b[i-1].multiply(x2);
int T = cin.nextInt();
for(int t=1;t<=T;t++){
BigInteger n=cin.nextBigInteger();
BigInteger m=cin.nextBigInteger();
BigInteger top = n.add(m.subtract(x1)).divide(m);
int len = 0;
while(b[len].compareTo(top)<=0) {
len++;
//System.out.println(b[len]);
}
BigInteger res = BigInteger.ZERO;
for(int l=len;l>=0;l--){
if(n.compareTo( b[l].subtract(x1).multiply(m)) >0 ){
BigInteger tmp = n.divide(b[l]);
if(tmp.compareTo(m)>0) tmp=m;
n = n.subtract( tmp.multiply(b[l]) );
res = res.add(b[l]);
}
}
System.out.println(res);
}
}
}

zoj 3988(H)

题目要求

定义一个二元组(a,b):如果满足a+b为质数
现在要在n个数字中选最多k个二元组使得这些选出数字的并集最大

参考AC代码

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
71
72
73
74
75
76
77
78
#include<bits/stdc++.h>
#define N 2000000
#define maxn 3050
#define mm(a,b) memset(a,b,sizeof(a))
using namespace std;
int t,n,k,top;
int linker[maxn],a[maxn],prime[N+50];
bool used[maxn],p[N+50];
vector<int>g[maxn];
int vis[maxn];
void init(){
memset(p,0,sizeof(p));
top=0;
for(int i=2;i<=N;++i){
if(!p[i]) prime[++top]=i;
for(int j=1;j<=top;++j) {
if(i*prime[j]>N) break;
p[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
bool dfs(int u){
used[u]=true;
for(int i=0;i<(int)g[u].size();i++){
int next=g[u][i];
if(!used[next]){
used[next]=true;
if(linker[next]==-1 || dfs(linker[next])){
linker[next]=u;
linker[u]=next;
return true;
}
}
}
return false;
}
int hungary(){
int ans=0;
mm(linker,-1);
for(int i=1;i<=n;i++){
if(vis[i] && linker[i]==-1){
mm(used,0);
if(dfs(i)) ans++;
}
}
return ans;
}
int main(){
// freopen("input.txt","r",stdin);
init();
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i=0;i<=n;i++) g[i].clear();
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
mm(vis,0);
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int temp=a[i]+a[j];
if(!p[temp]){
g[i].push_back(j);
g[j].push_back(i);
vis[i]=vis[j]=1;
}
}
}
int ans=hungary();
int cnt=0;
for(int i=1;i<=n;i++){
if(vis[i] && linker[i]==-1) cnt++;
}
if(ans>=k) printf("%d\n",2*k);
else{
printf("%d\n",2*ans+min(k-ans,cnt));
}
}
}

思路

二分图匹配
本题可以按照奇偶性分成二分图 只有奇数+偶数=奇数才可能为质数 但是存在1+1=2的特殊情况
所以采用拆点的方法 在原图上跑匈牙利 与原本把原图拆成二分图的匈牙利模版略有不同
由于本题要打印匹配的点 所以dinic比较麻烦 还是采用匈牙利
贪心策略:如果匹配的二元组比k大 那么答案就是2×k
否则答案就是已经匹配的ans个贡献的2×ans个数字加上剩下孤立点能与prime set相连的个数

zoj 3992(L)

题目要求

有1-n n个字符 L表示往左走一格 R表示往右走一格 给出初始位置m 如果走到1位置或者n位置 游戏结束
游戏开始前可以调整一些格子的L和R值 使得可以逃脱 求最小的修改次数

参考AC代码

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
#include<bits/stdc++.h>
#define maxn 100050
using namespace std;
int t,n,m;
char s[maxn];
int main(){
// freopen("input.txt","r",stdin);
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
scanf("%s",s+1);
int ans1=0,ans2=0;
if(s[m]=='L'){
for(int i=m-1;i>1;i--){
if(s[i]=='R') ans1++;
}
ans2++;
for(int i=m+1;i<n;i++){
if(s[i]=='L') ans2++;
}
printf("%d\n",min(ans1,ans2));
}
else{
for(int i=m+1;i<n;i++){
if(s[i]=='L') ans1++;
}
ans2++;
for(int i=m-1;i>1;i--){
if(s[i]=='R') ans2++;
}
printf("%d\n",min(ans1,ans2));
}
}
return 0;
}

思路

模拟
往左走和往右走 取min即可

文章目录
  1. 1. 2017ccpc秦皇岛
    1. 1.1. zoj 3981(A)
      1. 1.1.1. 题目要求
      2. 1.1.2. 参考AC代码
      3. 1.1.3. 思路
    2. 1.2. zoj 3983(C)
      1. 1.2.1. 题目要求
      2. 1.2.2. 参考AC代码
      3. 1.2.3. 思路
    3. 1.3. zoj 3987(G)
      1. 1.3.1. 参考AC代码
    4. 1.4. zoj 3988(H)
      1. 1.4.1. 题目要求
      2. 1.4.2. 参考AC代码
      3. 1.4.3. 思路
    5. 1.5. zoj 3992(L)
      1. 1.5.1. 题目要求
      2. 1.5.2. 参考AC代码
      3. 1.5.3. 思路
|