USACO section 1.1 C++题解

时间:2023-03-09 20:44:18
USACO section 1.1 C++题解

USACO section1.1:
DONE 2017.03.03 TEXT Submitting Solutions
DONE 2017.03.04 PROB Your Ride Is Here [ANALYSIS]
DONE 2017.03.04 TEXT Contest Problem Types
DONE 2017.03.04 TEXT Ad Hoc Problems
DONE 2017.03.04 PROB Greedy Gift Givers [ANALYSIS]
DONE 2017.03.04 PROB Friday the Thirteenth [ANALYSIS]
DONE 2017.03.04 PROB Broken Necklace [ANALYSIS]
由上可见section1.1*有四道题,没有考察算法,只是单纯看思考是否到位以及细心程度。

Prob1:Your Ride Is Here(水题)
题意:input给出两个全部由大写字母组成的单词, 每个字母对应一个数字(A-1,B-2……),
两个单词中的字母分别相乘,得到两个数字, 判断这两个数字%47的余数是否相等。

NOTE:由于数据很小,无须担心溢出,但是保险起见,还是在每次运算的过程中取余。(a%b)*(c%b) = (a*c)%b;

源代码:

 /*
ID:kongse_1
PROG:ride
LANG:C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MOD = ;
string a, b;
int num1= ,num2=;
int main()

 freopen("ride.in", "r", stdin);
 freopen("ride.out", "w", stdout);
 cin >> a >> b;
 
 for(int i = ; i != a.size(); ++i)
  num1 = (num1*(a[i]-'A'+))%MOD;
 for(int i = ; i != b.size(); ++i)
  num2 = (num2*(b[i]-'A'+))%MOD;
 
 if(num1 == num2) cout << "GO" << endl;
 else cout << "STAY" << endl;
 fclose(stdin);
 fclose(stdout);
 return ;
}

Prob2:Greedy Gift Givers (水题)
题意:有n个人,没人开始身上有0块钱,每个人选择掏出x的钱给他指定的n个人买礼物,他指定的人每个人得到x/n块钱,若除不尽(x%n)则多出来的零钱归他自己。输出一轮之后每个人对应的钱数(可以是负的...)。

P.S:本来开始想要用map做一一映射,结果map自带排序,把原来输入的顺序搞没了,于是乎只能拿俩数组维护。

源代码:

 /*
ID:kongse_1
PROG:gift1
LANG:C++
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = ;
string x[maxn], y[maxn], z;
int num, sum, n, money[maxn];
int find_(string curr)
{
 for(int i = ; i != num; ++i)
 {
  if(x[i] == curr) return i;
 }
}
void calculate_(int a, int b)
{
 money[a] -= b;
 return ;
}
int main(){
 freopen("gift1.in", "r", stdin);
 freopen("gift1.out", "w", stdout);
 
 cin >> num;
 
 for(int i = ; i != num; ++i)
 {
  cin >> x[i];
 }
 
 for(int i = ; i != num; ++i)
 {
  cin >> z >> sum >> n; 
  if(n)
  {
   calculate_(find_(z), sum-sum%n);
   for(int j = ; j != n; ++j)
   {
    cin >> y[j];
    calculate_(find_(y[j]), -sum/n);
   } 
  }
 }
 
 for(int i = ; i != num; ++i)
 {
  cout << x[i] << " " << money[i] << endl;
 }
 fclose(stdin);
 fclose(stdout);
 return ;
}

Prob3:Friday the Thirteenth
题意:已知1900年1月1日是周一,统计包括1900年在内的N年间,每月13号是周一——周日的次数。

NOTE1:得到1900年1月13日是周六,根据每个月的天数算出下一个月13日是星期几,注意判断闰年即可。

NOTE2:如果按照每年作为单位一步步求,会出现一个问题:每一年算的第12次实际上算的是下一年的1月13日(+31即是度过了12月份到了一月),所以算的最后一年的循环要特判。
源代码:

 /*
ID:kongse_1
PROG:friday
LANG:C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = ;
int month[maxn]={,,,,,,,,,,,,}, N, times[maxn], curr = ;
int whether(int year)
{
 if(year% == || (year% == && year% != )) return ;
 return ;
}
void caculate_(int year)
{
 if(year == +N) return ;
 
 if(whether(year)) month[] = ;
 else month[] = ;
 
 for(int i = ; i != ; ++i)
 {
  curr = (curr+month[i])%;
  if(i == && year == +N-) break;
  ++times[curr];
 }
 caculate_(year+);
}
int main()
{
 freopen("friday.in", "r", stdin);
 freopen("friday.out", "w", stdout);
 
 cin >> N;
 
 ++times[];
 caculate_();
 
 cout << times[] << " ";
 for(int i = ; i != ; ++i)
 {
  cout << times[i];
  if(i != ) cout << " ";
 }
 cout << endl;
 
 fclose(stdin);
 fclose(stdout);
 return ;

Prob4:Broken Necklace(有点意思)
题意:一串项链有三种颜色:红(r),蓝(b),白(w)。从中间某一处断开,从断开的两边分别去从头取颜色相同的珠子(两边右的可摘取数,然后从两个序列中找到a[i]+b[i+1]最大值(因为是从中间断的两川,所以一定是相邻的且向左的是第i个,向右的是第(i+1)%n)个。(注意,这是一串项链,首尾相连,是个循环队列)。

而算出没一个的向左区和向右取的值也很简单,不需要每个都算,例如算出第i个可以向左取m个,那么第(i-1)个,即他的左边一定只能取(m-1)个(m!=1),m = 1即只有自己。当出现左边的颜色与当前颜色不同时再重新计算。但是有一个例外。

我们观察这样的一串:bbwbwrrwrwr 第一个b是5,第五个w则应该是1,但是事实上第五个应该是7,因为它跟右边的红色也可以相连。所以我们得到特判:当上一个是2并且当前是白色(w)时应重新计算(即w是某队队尾)。

源代码:

 /*
ID:kongse_1
PROG:beads
LANG:C++
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
using namespace std;
const int maxn = ;
string x;
int n, num[][maxn], max_;
int whether(char a, char b)
{
 if(a+b == 'r'+'b') return ;
 return ;
}
void calculate_(int curr, string y)
{
 char last = x[curr];
 if(y == "left")
 {
  int wh = ;
  num[wh][curr] = ;
  for(int i = (curr-+n)%n;i != curr ; i = (i-+n)%n)
  {
   if(x[i] == last || x[i] == 'w' || last == 'w')
   {
    if(last == 'w') last = x[i];
    ++num[wh][curr];
   }
   else break;  
  }
 }
 
 else
 {
  int wh = ;
  num[wh][curr] = ;
  for(int i = (curr+)%n; i != curr ; i = (i++n)%n)
  {
   if(x[i] == last || x[i] == 'w' || last == 'w')
   {
    if(last == 'w') last = x[i];
    ++num[wh][curr];
   }
   else break;
  }
 }
 return ;
}
int main()
{
 freopen("beads.in", "r", stdin);
 freopen("beads.out", "w", stdout);
 
 cin >> n >> x; 
 
 for(int i = ; i != n; ++i)
 {
  if( !i || (num[][(i-+n)%n] == && x[i] == 'w') || whether(x[(i-+n)%n],x[i]) )
   calculate_(i, "right");
   else num[][i] = num[][i-]-;
 }
 
 for(int i = n-; i != -; --i)
 {
  if( i == n- || (num[][(i+)%n] == && x[i] == 'w') || whether(x[(i+)%n],x[i]) )
   calculate_(i, "left");
  else num[][i] = num[][i+]-;
 }
 
 for(int i = ; i != n; ++i){
 
  max_ = max(max_, num[][i]+num[][(i-+n)%n] ); 
 }
 
 cout <<((max_<n)?max_:n) << endl;
 
 fclose(stdin);
 fclose(stdout);
  
 return ;
}

自此,USACO section1.1便全部完成了。
箜瑟_qi 2016.03.04