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;
}