资格赛

1 算日期

主要是要算[a,b]之间被k整除数有多少


#include<cstdio>
typedef long long int LL;
#include <iostream>
#include<cstring>
#include "assert.h"
using namespace std;

char a[200],b[200],c[200], s[200];
LL func(LL a, LL b, int k){
  LL a1 = (a+k-1)/k;
  LL b1 = b/k;
  return b1-a1+1;
}

int month( char a[200] )
{
  if ( strcmp( a, "January" ) == 0 ) {
    return 1;
  }
  if ( strcmp( a, "February" ) == 0 )
  {
    return 2;
  }
  if ( strcmp( a, "March" ) == 0 )
  {
    return 3;
  }
  if ( strcmp( a, "April" ) == 0 )
  {
    return 4;
  }
  if ( strcmp( a, "May" ) == 0 )
  {
    return 5;
  }
  if ( strcmp( a, "June" ) == 0 )
  {
    return 6;
  }
  if ( strcmp( a, "July" ) == 0 )
  {
    return 7;
  }
  if ( strcmp( a, "August" ) == 0 )
  {
    return 8;
  }
  if ( strcmp( a, "September" ) == 0 )
  {
    return 9;
  }
  if ( strcmp( a, "October" ) == 0 )
  {
    return 10;
  }
  if ( strcmp( a, "November" ) == 0 )
  {
    return 11;
  }
  if ( strcmp( a, "December" ) == 0 )
  {
    return 12;
  }
  assert(1);
  return 1;
}
int main()
{
  int cas;
  cin>>cas;
  cin.get();
  for(int cc=1; cc<=cas; cc++)
  {
    int a1, b1, a2, b2;
    LL c1, c2;
    cin.getline(s, 200);
    sscanf(s, "%s %d, %lld", a, &b1, &c1);
    a1 = month(a);
    cin.getline(s, 200);
    sscanf(s, "%s %d, %lld", a, &b2, &c2);
    a2 = month(a);

    //cout<<a1<<":"<<b1<<":"<<c1<<endl;
    //cout<<a2<<":"<<b2<<":"<<c2<<endl;

    if ( a1 == 1 || ( a1 == 2 && b1 <= 29 ) ) //@error: b1 mistaken as b2 by sb_zhenyu > <
      c1 = c1;
    else c1 = c1 + 1;

    if ( a2 >= 3 || ( a2 == 2 && b2 == 29 ) )
      c2 = c2;
    else c2 = c2 - 1;

    int t = func(c1, c2, 4)-func(c1, c2, 100)+func(c1, c2, 400);
    cout<<"Case #"<<cc<<": "<<t<<endl;
  }
  return 0;
}		

2 计算回文个数 

o(N^3) 解法

 <j, k> = <j+1, k> + E(<j,<j+1, l-1>, l>  if s[j] == s[l],其中j<=l<=k)  即分为有j和没j两种情况。

#include <iostream>
#include <vector>
using namespace std;

int func(string &s){
  int n = s.length();
  vector<vector<int> > num(n, vector<int>(n, 0));
  for(int i = 0; i<n; i++)  num[i][i] = 1;
  for(int i = 2; i<=n; i++){
    for(int j = 0; j<n && j+i-1<n; j++){
      int k = j+i-1;
      //cal num[j][k]
      
      //without element j: [j+1,k]
      int t = num[j+1][k];

      //with element j: 
      //<[j, l]> => <j, [j+1, l-1], l>
      for(int l = j; l<=k; l++){
        if(s[j] == s[l]){
          t += 1;
          if(l-1>=j+1) t+= num[j+1][l-1];
        }
      }

      num[j][k] = t;
    }
  }
  return num[0][n-1];
}

int main(){
  int n; cin>>n;
  for(int i = 0; i<n; i++){
    string s; cin>>s;
    cout<<"Case #"<<i+1<<": "<<func(s)<<endl;
  }
  return 0;
}

O(n^2)解法 1

[j, k] =  [j+1, k] + [j, k-1] - [j+1, k-1]  (去重) +  [j, [j+1, k-1], k]  (if s[j]==s[k])

#include <iostream>
#include <vector>
typedef long long int LL;
using namespace std;

LL func(string &s){
  int n = s.length();
  vector<vector<LL> > num(n, vector<LL>(n, 0));
  for(int i = 0; i<n; i++)  num[i][i] = 1;
  for(int i = 2; i<=n; i++){
    for(int j = 0; j<n && j+i-1<n; j++){
      int k = j+i-1;
      
      //<j, k> = <j+1,k> + <j, k-1> - <j+1, k-1> + cnt(<j, [j+1, k-1], k>, if s[j] == s[k]) 
      int t = num[j+1][k]+num[j][k-1];
      if(i>2) t -= num[j+1][k-1];
      
      if(s[j] == s[k]) {
          t += 1;
          if(i>2) t += num[j+1][k-1];
      }
      
      num[j][k] = t;
    }
  }
  return num[0][n-1];
}

int main(){
  int n; cin>>n;
  for(int i = 0; i<n; i++){
    string s; cin>>s;
    cout<<"Case #"<<i+1<<": "<<func(s)<<endl;
  }
  return 0;
}


O(n^2)解法2

num[j][i]  记录起始于j,终止在i或i之前的回文数量,最外层循环i, 则num[][]可以少去一维数组。

则num[j][i] = num[j][i-1] + { 1 + sum{ num[k][i-1]  |  j<k<=i-1}  | if s[j] == s[i] },

计算sum{ num[k][i-1] | j<k<=i-1 } 的过程可以沿着 i-1 -> 0方向计算,从而O(n)时间完成。 

所以最后只要两重循环: for i { for k {} for j {} }

#include <iostream>
#include <vector>
typedef long long int LL;
using namespace std;

int func(string &s){
  int n = s.length();
  vector<LL > num(n, 0);

  for(int i = 0; i<n; i++){
    // num[k] 记录以k为起始元素,在i以内终止的回文个数
    num[i] = 1;

    // update <j, i>
    LL t = 0;
    for(int j = i-1; j>=0; j--){
      //<j, i>  = <j, i-1> + {sum{ <k, i-1>, j<k<=i-1 } + 1, if s[j]==s[i]}
      LL tmp = t;
      t += num[j];
      if(s[j] == s[i]){
        num[j] += tmp + 1;
      }
    }
  }
  LL sum = 0;
  for(int i = 0; i<n; i++) 
    sum += num[i];
  return sum;
}

int main(){
  int n; cin>>n;
  for(int i = 0; i<n; i++){
    string s; cin>>s;
    cout<<"Case #"<<i+1<<": "<<func(s)<<endl;
  }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值