2015-2016 ACM-ICPC, NEERC, Northern Subregional Contest 训练报告

题目链接:http://codeforces.com/gym/100801

训练情况:AC8题,竟然读错了一道题,wa了挺多发。

说明:AC的代码中加了文件读入。

Problem A. Alex Origami Squares

题意:给你一个h*w的矩形,让你分成三个正方形,输出正方形的最大边长。

分析:直接在分成2*2份 3*1份 1*3份,取max就可以了

AC代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5+5;

double h, w;

int main () {
    freopen("alex.in", "r", stdin);
    freopen("alex.out", "w", stdout);
    cin >> h >> w;
    double ans = 0;
    ans = max(ans, min(h*1.0/3, w));
    ans = max(ans, min(h, w*1.0/3));
    ans = max(ans, min(h*1.0/2, w*1.0/2));
    printf("%.3lf
", ans);
    return 0;
}
View Code

Problem B. Black and White

题意:给你b和w,然后让你构造一个n*m的矩阵,是的‘@’符号的联通块个数时b,‘.’的联通块个数是w。

分析:如果b和w一样,我们可以直接输出@和.间隔。否则我们假设b小于w,然后接下来的2*(b-1)行,我们交叉输出@@@和、、、,这样@还差一个联通块,.还差w-b+1个联通块。接下来我们输出2*(w-b+1)行,交叉输出@@@和@.@,就可以保证输出满足要求了。b>w交换一下就可以。

AC代码:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main(){
 6     ios_base::sync_with_stdio(false);
 7     cin.tie(0);
 8     freopen("black.in","r",stdin);
 9    freopen("black.out","w",stdout);
10     int b,w,r,c;
11     while(cin>>b>>w){
12 
13         if(b==w){
14             cout<<1<<" "<<b+w<<endl;
15             for(int i=1;i<=b+w;i++){
16                 if(i%2==0){
17                     cout<<"@";
18                 }
19                 else cout<<".";
20             }
21             cout<<endl;
22         }
23         else {
24             char s1='@',s2='.';
25             if(b>w){
26                 swap(b,w);
27                 swap(s1,s2);
28             }
29             int d=min(b,w);
30             d--;
31             cout<<d*2+max(b-d,w-d)*2<<" "<<3<<endl;
32             for(int i=1;i<=d*2;i++){
33                 if(i%2==1){
34                     cout<<s1<<s1<<s1<<endl;
35                 }
36                 else cout<<s2<<s2<<s2<<endl;
37             }
38             d=max(b-d,w-d);
39             for(int i=1;i<=d;i++){
40                 for(int j=1;j<=2;j++){
41                     if(j==1){
42                         cout<<s1<<s1<<s1<<endl;
43                     }
44                     else cout<<s1<<s2<<s1<<endl;
45                 }
46             }
47         }
48 
49     }
50 
51     return 0;
52 }
View Code

Problem C. Concatenation

题意:给你两个字符串s1和s2,然后在s1中选一个非空前缀,在s2中选一个非空后缀,问一共可以拼接多少不同的字符串。

分析:直接计算s2中每个字符的个数(最后一个字符不进行统计),直接用s1和s2字符串长度想乘,计算全部情况,减去重复的即可。枚举s1的每一个字符(不包括第一个)在第二个中出现几次,求和就是重复出现的个数(可以直接相乘,不用加法).

AC代码:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 string s;
 6 long long mp[505];
 7 int main(){
 8     ios_base::sync_with_stdio(false);
 9     cin.tie(0);
10     freopen("concatenation.in","r",stdin);
11     freopen("concatenation.out","w",stdout);
12     string s1,s2;
13     while(cin>>s1>>s2){
14         long long d1=s1.size();
15         long long d2=s2.size();
16         memset(mp,0,sizeof(mp));
17         long long result=0;
18         result=d1*d2;
19         for(int i=0;i<d2-1;i++){
20             mp[s2[i]]++;
21         }
22         for(int i=1;i<d1;i++){
23             result-=mp[s1[i]];
24         }
25         cout<<result<<endl;
26     }
27 
28     return 0;
29 }
View Code

Problem D. Distribution in Metagonia

题意:输入t,代表测试组数,接下来每次给你n,范围1e18,让你把n拆成不超过100个数字,这些数字的质因子只有2和3,。输出数字个数,然后

分析:比赛的时候是暴力dfs过的,但是看了一下自己的dfs还有别人的AC思路,应该是刚好这个dfs顺序和贪心的顺序一样,只不过及时return了。然后贪心的话,每次找n可以整除的最大的2^w,然后再找最大p使得2^w*3^p<=n。这样可以保证w是递减的,p是递增的,然后每两个数字都不会互相整除。

AC代码:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 long long mod=1e18;
 6 long long pw2[105],pw3[105];
 7 int up[105];
 8 struct st{
 9     int x,y;
10 }a[105];
11 int number=0;
12 int q=0;
13 void dfs(long long sum){
14    // cout<<sum<<endl;
15     if(sum==0) {q=1;return;}
16     if(q==1) return;
17     for(int i=60;i>=0;i--){
18         if(sum%pw2[i]!=0) continue;
19         for(int j=up[i];j>=0;j--){
20             if(sum>=pw2[i]*pw3[j]){
21                 a[number].x=i;
22                 a[number].y=j;
23                 number++;
24                 sum-=pw2[i]*pw3[j];
25                 dfs(sum);
26                 if(q==1)return;
27                 sum+=pw2[i]*pw3[j];
28                 number--;
29             }
30         }
31     }
32 }
33 int main(){
34     ios_base::sync_with_stdio(false);
35     cin.tie(0);
36     pw2[0]=1;
37     pw3[0]=1;
38     for(int i=1;i<=60;i++){
39         pw2[i]=pw2[i-1]*2;
40     }
41     for(int i=1;i<=38;i++){
42         pw3[i]=pw3[i-1]*3;
43     }
44     for(int i=0;i<=60;i++){
45         long long now=1;
46         for(int j=0;j<=40;j++){
47             if(pw2[i]*pw3[j]>mod){
48                 up[i]=j-1;
49                 break;
50             }
51             now*=3;
52         }
53     }
54     freopen("distribution.in","r",stdin);
55     freopen("distribution.out","w",stdout);
56     int t;
57     long long n;
58     cin>>t;
59     while(t--){
60         number=0;
61         q=0;
62         cin>>n;
63         dfs(n);
64         cout<<number<<endl;
65         for(int i=0;i<number;i++){
66             if(i!=0) cout<<" ";
67             cout<<pw2[a[i].x]*pw3[a[i].y];
68         }
69         cout<<endl;
70     }
71     return 0;
72 }
View Code

Problem E. Easy Arithmetic

题意:就是给你一个运算式子,然后你可以添加+或者-,使得运算结果最大。

分析:显然如果是加法,我们不需要添加,如果是减法,只需要在第一个数字之后添加+就可以了。添加加的前提是后一个是数字。

AC代码:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 int main(){
 6     ios_base::sync_with_stdio(false);
 7     cin.tie(0);
 8     freopen("easy.in","r",stdin);
 9     freopen("easy.out","w",stdout);
10     string s;
11     while(cin>>s){
12         int d=s.size();
13         int p=0;
14         for(int i=0;i<d;i++){
15             //cout<<i<<endl;
16             if(s[i]=='-'){
17                 p=1;
18                 cout<<s[i];
19                 i++;
20                 if(i<d){
21                     cout<<s[i];
22                 }
23             }
24             else if(p==1){
25                 if(s[i]=='0'){
26                     cout<<"+"<<s[i];
27                 }
28                 else {
29                     if(s[i]=='+'){
30                         cout<<s[i];
31                         p=0;
32                         continue;
33                     }
34                     cout<<"+";
35                     cout<<s[i];
36                     p=0;
37                 }
38             }
39             else {
40                 cout<<s[i];
41             }
42         }
43         cout<<endl;
44     }
45 
46     return 0;
47 }
View Code

Problem H. Hash Code Hacker

题意:给你一个k,然后让你构造k个字符串,使得字符串按照题目给的哈希公式哈希值相同。

分析:显然哈希公式是31进制,因此上一个字符-1,下一个字符+31就可以了。例如BB和Aa是等价的,可以构造一个长度为200的BBBBB字符串,然后选取两处替换成Aa就可以了。

AC代码:

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 string s;
 6 int main(){
 7     ios_base::sync_with_stdio(false);
 8     cin.tie(0);
 9     freopen("hash.in","r",stdin);
10     freopen("hash.out","w",stdout);
11     int n;
12     s="";
13     for(int i=1;i<=200;i++){
14         s+="B";
15     }
16     while(cin>>n){
17         int ans=0;
18         for(int i=0;i<100;i++){
19                 if(ans==n) break;
20             for(int j=i;j<100;j++){
21                 ans++;
22                 if(i==j){
23                     s[i*2]='A';
24                     s[i*2+1]='a';
25                     cout<<s<<endl;
26                     s[i*2]='B';
27                     s[i*2+1]='B';
28                 }
29                 else {
30                     s[i*2]='A';
31                     s[i*2+1]='a';
32                     s[j*2]='A';
33                     s[j*2+1]='a';
34                     cout<<s<<endl;
35                     s[i*2]='B';
36                     s[i*2+1]='B';
37                     s[j*2]='B';
38                     s[j*2+1]='B';
39                 }
40                 if(ans==n) break;
41             }
42         }
43     }
44 
45     return 0;
46 }
View Code

Problem J. Journey to the “The World’s Start”

题意:给你n和t,n代表n个站台,t代表花费的时间,然后接下来一行给你n-1个数字,分别代表每次可以走小于等于i站的地铁票的价格,每种票买到以后可以无限使用,再下来一行给你n-2个数字,代表你在第2到第n-1站下车再上车花费的时间。现在问你从1出发,在花费时间小于等于t的情况下,最少花费多少可以到达n。(从1到n车上需要花费n-1时间)

分析:首先对于题目,我们需要知道两点:1.如果x站的票可以在t时间内到达,那么x+1站的票也一定可以到达。2.一定是只买一种票花费最少。那么我们就可以二分x,判断x站的票是否可以达到我们可以dp+线段树维护,时间复杂度nlogn,然后对于每一个满足的x,维护一下价钱花费的后缀最小值,代表比x大的票都可以到达的最小花费。这样就可以完成这道题,总时间复杂度nloglog。(借用了一发赤耳的线段树模板)

AC代码:

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
  4 #define mem(a,b) memset(a,b,sizeof(a))
  5 #define FIN freopen("in.txt","r",stdin)
  6 #define ls (id<<1)
  7 #define rs ((id<<1)|1)
  8 #define mid ((l+r)>>1)
  9 typedef unsigned long long ULL;
 10 typedef long long LL;
 11 
 12 const int maxn = 50000+5;
 13 
 14 int n, price[maxn];
 15 LL t, a[maxn],b[maxn];
 16 
 17 struct Node {
 18     LL minx;
 19 } node[maxn*4];
 20 void pushUp (int id, int l, int r) {
 21     node[id].minx = min(node[ls].minx, node[rs].minx);
 22     return ;
 23 }
 24 void build (int id, int l, int r) {
 25     if (l == r) {
 26         node[id].minx = a[l];
 27         return ;
 28     }
 29     build(ls, l, mid);
 30     build(rs, mid+1, r);
 31     pushUp(id, l, r);
 32 }
 33 void update (int id, int l, int r, int p, LL val) {
 34     if (l > r) return ;
 35     if (l == r && l == p) {
 36         node[id].minx = val;
 37         return ;
 38     }
 39     if (p <= mid) update(ls, l, mid, p, val);
 40     else if (p > mid)
 41         update(rs, mid+1, r, p, val);
 42     pushUp(id, l, r);
 43 }
 44 LL query (int id, int l, int r, int ql, int qr) {
 45     if (l == ql && r == qr) return node[id].minx;
 46     if (qr <= mid) return query(ls, l, mid, ql, qr);
 47     else if (ql > mid)
 48         return query(rs, mid+1, r, ql, qr);
 49     else {
 50         return min(query(ls, l, mid, ql, mid), query(rs, mid+1, r, mid+1, qr));
 51     }
 52 }
 53 bool judge(int x){
 54     for(int i=3;i<=n;i++){
 55         long long d=query(1,1,n,max(i-x,1),i-1)+query(1,1,n,i,i);
 56         update(1,1,n,i,d);
 57     }
 58     if(query(1,1,n,n,n)<=t) return true;
 59     return false;
 60 }
 61 void up(){
 62     for(int i=1;i<=n;i++){
 63         a[i]=b[i];
 64     }
 65     build(1,1,n);
 66 }
 67 int main () {
 68     ios_base::sync_with_stdio(false);
 69     cin.tie(0);
 70     freopen("journey.in","r",stdin);
 71     freopen("journey.out","w",stdout);
 72     cin>>n>>t;
 73     t -= (n-1);
 74     for (int i = 1; i <= n-1; ++i)
 75         cin >> price[i];
 76     for(int i=n-2;i>=1;i--){
 77         price[i]=min(price[i+1],price[i]);
 78     }
 79     b[1]=0;
 80     b[n]=0;
 81     for (int i = 2; i <= n-1; ++i)
 82         {cin >> a[i];
 83             b[i]=a[i];
 84         }
 85     a[1] = a[n] =0;
 86     build(1, 1, n);
 87     int result=100005;
 88     int low=1,high=n-1;
 89     while(low<=high){
 90         int md=(low+high)/2;
 91         if(judge(md)){
 92             high=md-1;
 93             result=min(result,price[md]);
 94         }
 95         else {
 96             low=md+1;
 97         }
 98         up();
 99     }
100     cout<<result<<endl;
101     return 0;
102 }
View Code

Problem L. Lucky Chances

题意:就是给你一个r*c的数组,然后对于每一个数字,如果他在上下左右四个方向,有几个方向是最大的,就可以得几分,问你这个数组一共可以得几分。

分析:维护下行列前后缀最大值就可以,然后枚举就行了。(这个人代码真丑,竟然出现在我的博客上)

AC代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define IO ios_base::sync_with_stdio(0),cin.tie(0)
 4 #define mem(a,b) memset(a,b,sizeof(a))
 5 #define FIN freopen("in.txt","r",stdin)
 6 typedef unsigned long long ULL;
 7 typedef long long LL;
 8 
 9 const int maxn = 100+5;
10 
11 int n, m, a[maxn][maxn], h1[maxn][maxn], h2[maxn][maxn], l1[maxn][maxn], l2[maxn][maxn];
12 
13 int main () {
14     freopen("lucky.in", "r", stdin);
15     freopen("lucky.out", "w", stdout);
16     //FIN;
17     cin >> n >> m;
18     for (int i = 1; i <= n; ++i) {
19         for (int j = 1; j <= m; ++j)
20             cin >> a[i][j];
21     }
22     for (int i = 1; i <= n; ++i) {
23         for (int j = 1; j <= m; ++j) {
24             h1[i][j] = max(h1[i][j-1], a[i][j]);
25         }
26     }
27     for (int i = 1; i <= m; ++i) {
28         for (int j = 1; j <= n; ++j) {
29             l1[i][j] = max(l1[i][j-1], a[j][i]);
30         }
31     }
32     for (int i = 1; i <= n; ++i) {
33         for (int j = m; j >= 1; --j) {
34             h2[i][j] = max(h2[i][j+1], a[i][j]);
35         }
36     }
37     for (int i = 1; i <= m; ++i) {
38         for (int j = n; j >= 1; --j) {
39             l2[i][j] = max(l2[i][j+1], a[j][i]);
40         }
41     }
42     int ans = 0;
43     for (int i = 1; i <= n; ++i) {
44         for (int j = 1; j <= m; ++j) {
45             int x = a[i][j];
46             if (x > h1[i][j-1])
47                 ans++;
48             if (x > h2[i][j+1])
49                 ans++;
50         }
51     }
52     for (int i = 1; i <= m; ++i) {
53         for (int j = 1; j <= n; ++j) {
54             int x = a[j][i];
55             if (x > l1[i][j-1])
56                 ans++;
57             if (x > l2[i][j+1])
58                 ans++;
59         }
60     }
61     cout << ans << endl;
62     return 0;
63 }
View Code
原文地址:https://www.cnblogs.com/ls961006/p/9004350.html