• 2017 ACM Arabella Collegiate Programming Contest(solved 11/13)


    省选考前单挑做点ACM练练细节还是很不错的嘛~

    福利:http://codeforces.com/gym/101350

    先来放上惨不忍睹的virtual participate成绩(中间跑去食堂吃饭于是浪费了一点时间)

    Problem A DNF

    Problem B 1Y(5min)

    Problem C 1Y(37min)

    Problem D 2Y(9min)

    Problem E 4Y(3h58min)

    Problem F DNF

    Problem G 1Y(4h13min)

    Problem H 1Y(13min)

    Problem I 1Y(1h7min)

    Problem J 1Y(1h26min)

    Problem K 1Y(2h36min)

    Problem L DNF

    Problem M 30Y(3h47min)

    先来大体上说一下,整个5h都还算ok,然而这个M题。。。事故啊。。。(之后会说)

    感觉这套题有点偏向化,思维量大代码量小,导致容易卡题,也容易柳暗花明。

    下面就是题解啦~

    Problem A:

    这是一个很不错的思维题啊!

    比较容易陷入误区的地方在于,这种三元集的题大部分人会先去考虑中间项,然而应该先考虑两边。

    我们将1的个数前缀和一下,于是观察出如果(i,j,k)满足题意,那么presum[i]和presum[k]有一些奥妙重重的关系,

    然后又发现一个惊人的事实:如果presum[i]和presum[k]满足的话,那么中间的j应该是有且仅有1个可能的,

    这样就可以统计答案了。

    时间复杂度O(n),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 typedef long long int64;
     4 const int N=220000;
     5 int n, z[N], num=0;
     6 char c[N];
     7 int64 calc ()
     8 {
     9     int64 ans=0;
    10     int cnt=0;
    11     for (int i=0; i<(int)strlen(c); i++) if (c[i]=='0') cnt++;
    12     else z[++num]=cnt+1, cnt=0;
    13     z[++num]=cnt+1;
    14     int64 a=0, b=0;
    15     for (int i=1; i<=num; i=i+2) a+=z[i];
    16     for (int i=2; i<=num; i=i+2) b+=z[i];
    17     ans=a*b;
    18     for (int i=1; i<=num; i++) ans-=2*z[i];
    19     ans+=z[1]+z[num];
    20     ans+=num-1;
    21     return ans;
    22 }
    23 int main ()
    24 {
    25     int t, n;
    26     scanf("%d", &t);
    27     for (int i=1; i<=t; i++)
    28     {
    29         scanf("%d%s", &n, c);
    30         num=0;
    31         printf("%I64d
    ", calc());
    32     }
    33     return 0;
    34 }

    Problem B:

    你会不会写程序呀~

    你会不会比大小呀~

    时间复杂度O(1),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int main()
     4 {
     5     int T;
     6     cin>>T;
     7     while (T--)
     8     {
     9         int a,b;
    10         cin>>a>>b;
    11         if (b>a) cout<<"WeWillEatYou"<<endl; else cout<<"FunkyMonkeys"<<endl;
    12     }
    13     return 0;
    14 }

    Problem C:

    首先这个题有两问,

    第一问的答案就是这n个数的总和,O(n)扫一下就好啦~

    第二问的答案就是这n个数的最大公约数,O(n)扫一下也好啦~

    时间复杂度O(n),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int T,n;
     4 int x[100007];
     5 long long ans1,ans2;
     6 int read()
     7 {
     8     int x=0,f=1;char ch=getchar();
     9     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    10     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    11     return x*f;
    12 }
    13 long long gcd(long long a,long long b)
    14 {
    15     if (b==0) return a;
    16     return gcd(b,a%b);
    17 }
    18 int main()
    19 {
    20     T=read();
    21     while (T--)
    22     {
    23         n=read();
    24         ans1=0,ans2=0;
    25         for (int i=1;i<=n;i++) 
    26         {
    27             x[i]=read();
    28             ans1+=x[i];
    29             ans2=gcd(x[i],ans2);
    30         }
    31         cout << ans1 << ' ' << ans2 << endl;
    32     }
    33     return 0;
    34 }

    Problem D:

    首先很容易发现,不管怎么操作,大家的相对奇偶性是不变的。

    然后发现所有数奇偶性相同是答案为yes的充要条件。(因为不可能小于0啊,如果小于0的话先大家都长高一下就好了~)

    时间复杂度O(n),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5     int x=0,f=1;char ch=getchar();
     6     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     7     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     8     return x*f;
     9 }
    10 int T;
    11 int h[100007];
    12 int main()
    13 {
    14     cin>>T;
    15     while (T--)
    16     {
    17         int n;
    18         n=read();
    19         for (int i=1;i<=n;i++) h[i]=read();
    20         bool check=true;
    21         for (int i=2;i<=n;i++) if (h[i]%2!=h[1]%2) check=false;
    22         if (check) cout <<"yes" << endl; else cout << "no" << endl;
    23     }
    24     return 0;
    25 }

    Problem E:

    这是个很有趣的题目呀~

    大家千万不要被质数这个条件所迷惑啊,这题和这个一点关系也没有。

    当n为偶数的时候,只需要先手取最中间两个,然后和后手对称取就能赢了,所以n>2且为偶数时,先手获胜。

    当n为奇数的时候,只需要先手取最中间三个,然后和对手对称取就能赢了,所以n>3且为奇数时,先手获胜。

    当n=1时,先手获胜。

    当n=2时,先手只能取1,后手也取1,后手获胜。

    当n=3时,先手只能取2,后手取1,后手获胜。

    所以这个题只有n=2或者n=3的时候后手获胜,其他情况都是先手获胜。

    自古博弈代码短~~~

    时间复杂度O(1),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5     int x=0,f=1;char ch=getchar();
     6     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     7     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     8     return x*f;
     9 }
    10 int T,n;
    11 int main()
    12 {
    13     T=read();
    14     while (T--)
    15     {
    16         n=read();
    17         if (n==2||n==3) cout << "second" << endl; else cout << "first" << endl;
    18     }
    19     return 0;
    20 }

    Problem G:

    这个题我是在比较靠后的时间去做的,

    第一眼。。。smg。。。完全不会

    第二眼。。。n和m这么大,连O(nm)都过不了。。。

    第三眼。。。这个k怎么才20啊。。。这不是瞎容斥一下就好了。。。

    我们枚举2^k种不同的情况,每个点能不能取,维护出x坐标最小最大值,y坐标最小最大值,剩下的全部数学手推即可。

    时间复杂度O(2^k),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5     int x=0,f=1;char ch=getchar();
     6     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     7     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     8     return x*f;
     9 }
    10 long long ans;
    11 int T,n,m,k,minx,maxx,miny,maxy;
    12 int x[25],y[25],path[25];
    13 void dfs(int x1,int cnt)
    14 {
    15     if (x1<=k)
    16     {
    17         dfs(x1+1,cnt);
    18         path[cnt+1]=x1;
    19         dfs(x1+1,cnt+1);
    20     } else if (cnt>0)
    21     {
    22         minx=100007,miny=100007;
    23         maxx=0,maxy=0;
    24         for (int i=1;i<=cnt;i++)
    25         {
    26             int t=path[i];
    27             minx=min(minx,x[t]);
    28             maxx=max(maxx,x[t]);
    29             miny=min(miny,y[t]);
    30             maxy=max(maxy,y[t]);
    31         }
    32         long long r=1LL*minx*miny*(n-maxx+1)*(m-maxy+1);
    33         if (cnt%2==1) ans-=r; else ans+=r;
    34     }
    35 }
    36 int main()
    37 {
    38     T=read();
    39     while (T--)
    40     {
    41         n=read(),m=read(),k=read();
    42         for (int i=1;i<=k;i++) x[i]=read(),y[i]=read();
    43         ans=((1LL*n*(n-1))/2+n)*((1LL*m*(m-1))/2+m);
    44         dfs(1,0);
    45         cout << ans << endl;
    46     }
    47     return 0;
    48 }

    Problem H:

    这个题模拟一下就好了吧,先扫一遍字母,再扫一遍看一下是否回文。

    时间复杂度O(n),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int T;
     4 string s;
     5 bool deal(char x)
     6 {
     7     if (x=='A'||x=='H'||x=='I'||x=='M'||x=='O'||x=='T'||x=='U'||x=='V'||x=='W'||x=='X'||x=='Y') return false;
     8     return true;
     9 }
    10 int main()
    11 {
    12     cin>>T;
    13     while (T--)
    14     {
    15         cin>>s;
    16         bool check=true;
    17         for (int i=0;i<s.length();i++) if (deal(s[i])) check=false;
    18         for (int i=0;i<s.length();i++) if (s[i]!=s[s.length()-i-1]) check=false;
    19         if (check) cout << "yes" << endl; else cout << "no" << endl;
    20     }
    21     return 0;
    22 }

    Problem I:

    这个题首先把符合条件的字母搞出来,然后我们枚举回文的中间点,往两侧扩展就行了。

    然而回文串有奇数长度,有偶数长度不太好处理。

    没关系,我们在每相邻的两个字母之间加一个"#"(任何从未出现的字符都可以),然后扫一下就行了。

    (其实这道题最长回文子串可以Manacher做啊,O(n)就够了,然而并不需要QWQ。。。)

    时间复杂度O(n^2),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int T;
     4 string s,ss;
     5 bool deal(char x)
     6 {
     7     if (x=='A'||x=='H'||x=='I'||x=='M'||x=='O'||x=='T'||x=='U'||x=='V'||x=='W'||x=='X'||x=='Y') return false;
     8     if (x=='#') return false;
     9     return true;
    10 }
    11 int main()
    12 {
    13     cin>>T;
    14     while (T--)
    15     {
    16         cin>>ss;
    17         int n=ss.length();
    18         s.clear();
    19         s+="#";
    20         for (int i=0;i<n;i++)
    21         {
    22             s+=ss[i];
    23             s+="#";
    24         }
    25         n=s.length();
    26         int ans=0;
    27         for (int i=0;i<n;i++)
    28         {
    29             int now=0,tot=0;
    30             while (i-now-1>=0&&i+now+1<n&&s[i-now-1]==s[i+now+1]&&(!deal(s[i-now-1]))) ++now;
    31             for (int j=i-now;j<=i+now;j++) if (s[j]!='#') ++tot;
    32             if (tot>ans&&(!deal(s[i]))) ans=tot;
    33         }
    34         cout << ans << endl;
    35     }
    36     return 0;
    37 }

    Problem J:

    看到这道题题目名字里面有个"physics"的时候吓坏我了一直不敢开,结果点进去一看。。。

    初中老师说过~~~弓形面积=扇形面积-三角形面积,

    扇形面积会不会呀~

    三角形面积会不会呀~

    编程会不会呀(逃。。。)

    时间复杂度O(1),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5     int x=0,f=1;char ch=getchar();
     6     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     7     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     8     return x*f;
     9 }
    10 int T,L,A;
    11 double ans;
    12 int main()
    13 {
    14     T=read();
    15     while (T--)
    16     {
    17         L=read(),A=read();
    18         ans=(double)A/360*L*L*M_PI;
    19         ans-=(double)0.5*L*L*sin((double)A/180*M_PI);
    20         printf("%.6lf
    ",ans);
    21     }
    22     return 0;
    23 }

    Problem K:

    我们先暴力扫描出这个集合,然后暴力一下就好了。

    时间复杂度O(n),代码如下:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int read()
     4 {
     5     int x=0,f=1;char ch=getchar();
     6     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     7     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     8     return x*f;
     9 }
    10 int T,a,b,n;
    11 int cnt[150];
    12 void deal(int n)
    13 {
    14     int t[15];
    15     memset(t,0,sizeof(t));
    16     while (n>0)
    17     {
    18         ++t[n%10];
    19         n=n/10;
    20     }
    21     int ans=0;
    22     for (int i=0;i<=9;i++) ans=max(ans,t[i]);
    23     for (int i=0;i<=9;i++) if (t[i]==ans) ++cnt[i];
    24 }
    25 int main()
    26 {
    27     T=read();
    28     while (T--)
    29     {
    30         memset(cnt,0,sizeof(cnt));
    31         a=read(),b=read(),n=read();
    32         for (int i=1;1LL*i*i*a+1LL*b*i<=n;i++)
    33             deal(1LL*i*i*a+1LL*b*i);
    34         int ans=0;
    35         for (int i=0;i<=9;i++) if (cnt[i]>cnt[ans]) ans=i;
    36         if (a+b>n) ans=-1;
    37         cout << ans << endl;
    38     }
    39     return 0;
    40 }

    Problem M:

    噩梦的一题。。。

    我先写了个二分。。。然后我用的是cin。。。惨遭卡常。。。

    于是写了个hash。。。惨遭卡常。。。

    然后cin改成了scanf。。。WA了。。。

    hash写跪了。。。终于过了。。。

    时间复杂度O(n),代码如下:

     1 #include <bits/stdc++.h>
     2 #define modp 100000007
     3 using namespace std;
     4 int read()
     5 {
     6     int x=0,f=1;char ch=getchar();
     7     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     8     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     9     return x*f;
    10 }
    11 int T,c,n;
    12 string s1;
    13 double s2;
    14 map<int,double> mp;
    15 double a;
    16 string r;
    17 int hash(string &s)
    18 {
    19     long long ans=0,now=1;
    20     for (int i=0;i<s.length();i++)
    21     {
    22         ans=(107LL*ans+1LL*now*(s[i]-'A'+1))%modp;
    23         now=(17LL*now)%modp;
    24     }
    25     return ans%modp;
    26 }
    27 int main()
    28 {
    29     //freopen("M.in","r",stdin);
    30     //freopen("M.out","w",stdout);
    31     T=read();
    32     while (T--)
    33     {
    34         c=read(),n=read();
    35         mp.clear();
    36         for (int i=1;i<=c;i++) 
    37         {
    38             char ch=getchar();
    39             while ((ch<'a'||ch>'z')&&(ch<'A'||ch>'Z')) ch=getchar();
    40             long long ans=0,now=1;
    41             while (ch!=' ')
    42             {
    43                 ans=(107LL*ans+1LL*now*(ch-'A'+1))%modp;
    44                 now=(17LL*now)%modp;
    45                 ch=getchar();
    46             }
    47             scanf("%lf",&s2);
    48             mp[ans%modp]=s2;
    49         }
    50         r="JD";
    51         mp[hash(r)]=1.0;
    52         double anss=0.0;
    53         for (int i=1;i<=n;i++)
    54         {
    55             scanf("%lf",&a);
    56             char ch=getchar();
    57             while ((ch<'a'||ch>'z')&&(ch<'A'||ch>'Z')) ch=getchar();
    58             long long ans=0,now=1;
    59             while (ch!='
    ')
    60             {
    61                 ans=(107LL*ans+1LL*now*(ch-'A'+1))%modp;
    62                 now=(17LL*now)%modp;
    63                 ch=getchar();
    64             }
    65             anss+=a*mp[ans%modp];
    66         }
    67         printf("%.6lf
    ",anss);
    68     }
    69     return 0;
    70 }

    写完啦~撒花~

  • 相关阅读:
    scala之伴生对象的继承
    scala之伴生对象说明
    “Failed to install the following Android SDK packages as some licences have not been accepted” 错误
    PATH 环境变量重复问题解决
    Ubuntu 18.04 配置java环境
    JDBC的基本使用2
    DCL的基本语法(授权)
    ZJNU 1374
    ZJNU 2184
    ZJNU 1334
  • 原文地址:https://www.cnblogs.com/Tommyr7/p/6743314.html
Copyright © 2020-2023  润新知