constint MAXN =100000;boolcheck(int n){while(n){if(n %10==5)returntrue;
n /=10;}returnfalse;}boolprime(int n){if(n <2)returnfalse;bool ret =true;for(int i =2; i * i <= n; i++){if(n % i ==0) ret =false;}return ret;}intmain(){int cnt =0;for(int i =1; i <= MAXN; i++)if(check(i)&&prime(i)) cnt++;
cout << cnt << endl;return0;}
int ans =0;int a[117]={7,2,12,5,9,9,8,10,7,10,5,4,5,8,4,4,10,11,3,8,7,8,3,2,1,6,3,9,7,1};int sum[117];voiddfs(int idex,int num){if(idex ==30){
ans =max(ans, num);return;}if(sum[idex]/3+ num < ans)return;//剪枝优化//不共用dfs(idex +1, num + a[idex]/3);//往后共用if(idex +2<30){int min_num =min(a[idex], a[idex +1]);
min_num =min(min_num, a[idex +2]);//共用最多能分几个for(int k =1; k <= min_num; k++){for(int i =0; i <3; i++) a[idex + i]-= k;dfs(idex +1, num + a[idex]/3+ k);for(int i =0; i <3; i++) a[idex + i]+= k;}}}intmain(){for(int i =29; i >=0; i--) sum[i]= sum[i +1]+ a[i];dfs(0,0);
cout << ans << endl;return0;}
constint MAXN =300+117;int n, m, k;
LL a, b, c, w;
LL harm[MAXN][MAXN];//炮弹的范围伤害
LL decrement[MAXN][MAXN];//耐久度的减少量int village[MAXN][MAXN];//村庄布局int q, id, x, y;
LL road, house, field, sum;int dx[8]={-1,-1,-1,0,0,1,1,1};int dy[8]={-1,0,1,-1,1,-1,0,1};boolcheck(int x,int y){//判断坐标是否合法if(x <0|| x >= n)returnfalse;if(y <0|| y >= m)returnfalse;returntrue;}voidsputtering(int x,int y){//往周围8个格子溅射伤害for(int i =0; i <8; i++){if(check(x + dx[i], y + dy[i]))
decrement[x + dx[i]][y + dy[i]]+= w;}}voidsolve(){int bex = x - k /2, bey = y - k /2;for(int i =0; i < k; i++){for(int j =0; j < k; j++){if(check(bex + i, bey + j)){
decrement[bex + i][bey + j]+= harm[i][j];if(id ==0)sputtering(bex + i, bey + j);}}}}voidpr(){for(int i =0; i < n; i++){for(int j =0; j < m; j++){if(village[i][j]==1){//road += min(decrement[i][j], a);
road += decrement[i][j]>= a;
sum +=min(decrement[i][j], a);}elseif(village[i][j]==2){//house += min(decrement[i][j], b);
house += decrement[i][j]>= b;
sum +=min(decrement[i][j], b);}else{//field += min(decrement[i][j], c);
field += decrement[i][j]>= c;
sum +=min(decrement[i][j], c);}}}
cout << road <<" "<< house <<" "<< field << endl;
cout << sum << endl;}intmain(){
cin >> n >> m;
cin >> a >> b >> c;
cin >> k >> w;for(int i =0; i < k; i++)for(int j =0; j < k; j++)
cin >> harm[i][j];for(int i =0; i < n; i++)for(int j =0; j < m; j++)
cin >> village[i][j];
cin >> q;while(q--){
cin >> id >> x >> y;
x--, y--;solve();}pr();return0;}
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
H. 程序设计:字符串
此题需要前置技能点:模运算,即89%M = (8*10%M + 9*1%M)%M。
先假设进制为10进制,题意为给定一个数,至多交换两位数字使得到的数字是M的倍数。
题目中说到多解输出字典序最小,则容易想到枚举。考虑一下复杂度,枚举交换的位置需要o(
n
2
n
2
),计算mod需要o(
n
1
n
1
),总的复杂度o(
n
3
n
3
)。
对多次取模操作进行优化,假设a=123%M,b=321%M,考虑123和321之间的关系:321 = 123 - 1*100 - 3*1 + 3*100 + 1*1,根据模运算则有b = (a - 1*100 - 3*1 + 3*100 + 1*1)%M。即假设交换任意i位置和j位置的数,A为交换前的值,B为交换后的值,有B = (A - i*
1
0
i
1
0
i
- j*
1
0
j
1
0
j
+ i*
1
0
j
1
0
j
+ j*
1
0
i
1
0
i
)%M,复杂度O(1)。
最后,进制为26,需要预处理一下幂次的取模,以及注意减法运算时答案的取正。
constint MAXN =2000+117;char s[MAXN];int len;int a[MAXN];int fact[MAXN];int M;int num, now;voidsub(int mul,int order){//now=now-mul*26^orderint sum = fact[order];
sum = sum * mul % M;
now =((now - sum)% M + M)% M;}voidadd(int mul,int order){//now=now+mul*26^orderint sum = fact[order];
sum = sum * mul % M;
now =(now + sum)% M;}voidinit(){//预处理幂次scanf("%s", s);scanf("%d",&M);
fact[0]=1;for(int i =1; i < MAXN; i++) fact[i]= fact[i -1]*26% M;
len =strlen(s);for(int i =0; i < len; i++){
a[i]= s[i]-'A';
num =(num *26+ a[i])% M;}}intmain(){init();if(num ==0)puts("0 0");else{bool pr =false;for(int i =0; i < len &&!pr; i++){for(int j =0; j < len &&!pr; j++){
now = num;sub(a[i], len -1- i);sub(a[j], len -1- j);add(a[i], len -1- j);add(a[j], len -1- i);if(now ==0){printf("%d %d\n", i +1, j +1);
pr =true;}}}if(!pr)puts("-1 -1");}return0;}
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
I. 程序设计:最短路
此题需要前置技能点:单源最短路Dij的堆优化
如果你会了Dij的堆优化,那么就可以做此题了。
题目要求从起点
到每个点再回来
的最短路径的总和。对于一个点,有:来回最短路 = 去最短路 + 回最短路。利用Dij可求得起点去每个点的最短路,回的最短路容易想到对每个点都用一遍Dij,但这种做法的复杂度o(
n
3
n
3
)。可以注意到,无论怎么样起点总是固定的,如若
将所有的边都反向
,则跑一遍Dij即可求得所有回来的最短路,如下图。
constint MAXN =6e4+117;int t;struct qnode {int v;
LL c;qnode(int _v =0, LL _c =0):v(_v),c(_c){}booloperator<(const qnode &r)const{return c > r.c;}};struct Edge {int v;
LL cost;Edge(int _v =0, LL _cost =0):v(_v),cost(_cost){}};
vector<Edge> E[2][MAXM];bool vis[MAXN];
LL dist[2][MAXN];voidDijstra(int flag,int n,int start){memset(vis,false,sizeof(vis));for(int i =1; i <= n; i++) dist[flag][i]=1e18;
priority_queue<qnode> que;while(!que.empty()) que.pop();
dist[flag][start]=0;
que.push(qnode(start,0));
qnode tmp;while(!que.empty()){
tmp = que.top();
que.pop();int u = tmp.v;if(vis[u])continue;
vis[u]=true;for(int i =0; i < E[flag][u].size(); i++){int v = E[flag][tmp.v][i].v;int cost = E[flag][u][i].cost;if(!vis[v]&& dist[flag][v]> dist[flag][u]+ cost){
dist[flag][v]= dist[flag][u]+ cost;
que.push(qnode(v, dist[flag][v]));}}}}voidaddedge(int flag,int u,int v, LL w){
E[flag][u].push_back(Edge(v, w));}int n, m;
LL sum;voidinit(){
sum =0;for(int i =0; i < MAXM; i++){
E[0][i].clear();
E[1][i].clear();}}intmain(){scanf("%d",&t);while(t--){init();scanf("%d%d",&n,&m);int u, v;
LL w;while(m--){scanf("%d %d %lld",&u,&v,&w);addedge(0, u, v, w);addedge(1, v, u, w);}Dijstra(0, n,1);Dijstra(1, n,1);for(int i =1; i <= n; i++) sum += dist[0][i]+ dist[1][i];printf("%lld\n", sum);}return0;}