9.24省赛题解
A Marjar Cola
题意
给你a、b和可乐瓶和可乐盖,你可以用x个可乐瓶或者y个可乐盖换一瓶可乐(包括1给可乐瓶和可乐盖),问最多能换多少瓶可乐
题解
考虑永远也换不完的情况
1,x == 1 || y == 1(a,b,x,y>=1)
2, x == 2 && y == 2 &&(a >= 2 || b >= 2)
#include <cstdio>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int MAX = 1e5 + 10;
const int INF = 1e9 + 7;
int main() {
int T;
scanf("%d", &T);
while(T--) {
int x, y, a, b;
scanf("%d%d%d%d", &x, &y, &a, &b);
if(x == 1|| y == 1 || (x == 2 && y == 2 && a >= 2)|| (x == 2 && y == 2 && b >= 2)) {
printf("INF\n");
continue;
}
int ans = 0;
while(1) {
if(a < x && b < y) break;
while(a >= x) {
int cnt = a / x;
ans += cnt;
a %= x;
a += cnt;
b += cnt;
}
while(b >= y) {
int cnt = b / y;
ans += cnt;
b %= y;
a += cnt;
b += cnt;
}
}
printf("%d\n", ans);
}
return 0;
}
C How Many Nines
题意
给你两个日期,问你这两个日期之间有多少个数字’9’
题解1
我的理解:计算两个日期之间的年份出现的9的次数 ,例如2017.7.8-2039.2.23先计算2017-2039(包括2017和2039) 在减去到2017.1.1到2017.7.7出现的9的次数,在加上2039.1.1到2039.2.23
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string>
#define ll long long
using namespace std;
const int MAX = 1e4 + 10;
const int INF = 1e9 + 7;
int a[13];//每月有几个9,一般情况下
int year[MAX];//每年出现9的次数
int run[MAX];//闰年的次数
int sumday[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
inline void init() {
for(int i = 1; i <= 12; i++) {
a[i] = 3;
}
a[2] = 2;
a[9] = 33;
run[1999] = 0;
int cnt = 0;
for(int i = 1999; i <= 10000; i++) {
if(i % 400 == 0 || (i % 100 != 0 && i % 4 == 0)) {
cnt++;
}
run[i] = cnt;
int cnt9 = 0;
if(i % 10 == 9) cnt9++;
if(i / 10 % 10 == 9) cnt9++;
if(i / 100 % 10 == 9) cnt9++;
if(i / 1000 % 10 == 9) cnt9++;
year[i] = cnt9;
}
for(int i = 1; i <= 12; i++) {
sumday[i] += sumday[i - 1];
}
}
ll solve(int y1, int y2) {//闭区间
ll ans = 0ll;
for(int i = y1; i < y2; i++) {
if(run[i] > run[i - 1]) {
ans += (366) * year[i] + 66;
}
else ans += 365 * year[i] + 65;
}
return ans;
}
int main() {
init();
int T;
scanf("%d", &T);
while(T--) {
int y1, m1, d1, y2, m2, d2;
scanf("%d%d%d %d%d%d", &y1, &m1, &d1, &y2, &m2, &d2);
ll ans = 0ll;
//开区间
d1--;
ans += solve(y1, y2);
//-前面的
ans -= (sumday[m1 - 1] + d1) * year[y1];
if(run[y1] > run[y1 - 1] && m1 >= 3) ans -= year[y1];
//月
for(int i = 1; i < m1; i++) ans -= a[i];
if(run[y1] > run[y1 - 1] && m1 >= 3) ans -= 1;
//日
if(m1 == 9) {
ans -= d1;
}
if(d1 >= 29) ans -= 3;
else if(d1 >= 19) ans -= 2;
else if(d1 >= 9) ans--;
//+后面的
//年
ans += (sumday[m2 - 1] + d2) * year[y2];
if(run[y2] > run[y2 - 1] && m2 >= 3) ans += year[y2];
//月
for(int i = 1; i < m2; i++) ans += a[i];
if(run[y2] > run[y2 - 1] && m2 >= 3) ans += 1;
//日
if(m2 == 9) {
ans += d2;
}
if(d2 >= 29) ans += 3;
else if(d2 >= 19) ans += 2;
else if(d2 >= 9) ans++;
printf("%lld\n", ans);
}
return 0;
}
题解2
具体看代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int MAX = 1e4 + 10;
int sumday[2][13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int sum9(int n) {
int ans = 0;
while(n) {
if(n % 10 == 9) ans++;
n /= 10;
}
return ans;
}
bool judge(int x) {
if((x % 400 == 0) || (x % 4 == 0 && x % 100 != 0)) return 1;
else return 0;
}
int sum[MAX][13][33];
void init() {
int presum = 0;
for(int year = 2000; year <= 9999; year++) {
for(int mon = 1; mon <= 12; mon++) {
int maxday = sumday[0][mon];
if(judge(year)) maxday = sumday[1][mon];
for(int day = 1; day <= maxday; day++) {
sum[year][mon][day] = presum + sum9(year) + sum9(mon)+ sum9(day);
presum = sum[year][mon][day];
}
}
}
}
int main() {
init();
int T;
scanf("%d", &T);
while(T--) {
int y1, y2, m1, m2, d1, d2;
scanf("%d%d%d %d%d%d", &y1, &m1, &d1, &y2, &m2, &d2);
int ans = sum[y2][m2][d2] - sum[y1][m1][d1] + sum9(y1) + sum9(m1) + sum9(d1);
printf("%d\n", ans);
}
}
F Intervals
题意
给出N给区间,问最少删除多少个区间,使得任意三个区间中至少有一个区间不相交
题解
将所有区间 以左端点为键值从小到大排序
然后三个三个一组 进行判断
如果 这三个中有两两相交的 那么就删去右端点最大的 因为这个区间对答案的贡献最小
然后三个区间当中没有两两相交的,那么下一次进来的区间就替换掉右端点最小的。
I Course Selection System
题意
( ∑ i = 1 m H x i ) 2 − ( ∑ i = 1 m H x i ) × ( ∑ i = 1 m C x i ) − ( ∑ i = 1 m C x i ) 2 (\sum_{i=1}^{m} H_{x_i})^2-(\sum_{i=1}^{m} H_{x_i})\times(\sum_{i=1}^{m} C_{x_i})-(\sum_{i=1}^{m} C_{x_i})^2 (i=1∑mHxi)2−(i=1∑mHxi)×(i=1∑mCxi)−(i=1∑mCxi)2 这样的式子,求这个式子的最大值。
题解
令 ( ∑ i = 1 m H x i ) 2 = X , ( ∑ i = 1 m C x i ) = Y (\sum_{i=1}^{m} H_{x_i})^2 = X, (\sum_{i=1}^{m} C_{x_i}) = Y (∑i=1mHxi)2=X,(∑i=1mCxi)=Y然后化简以后得到, ( X − Y ) × X − Y 2 (X - Y) \times X- Y ^ 2 (X−Y)×X−Y2所以当 Y Y Y固定, X X X越大越好,所以就dp 一下
dp[i]表示目前y的总和为i的情况下x的最大值。
//先放放,我需要再打一遍
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 50010;
int dp[maxn];
int h[maxn];
int c[maxn];
int main(){
int T;
scanf("%d" , &T);
while(T --){
int n;
scanf("%d" , &n);
int sum = 0;
for(int i =1 ; i <= n ; ++ i){
scanf("%d%d" , &h[i] , &c[i]);
sum += c[i];
}
memset(dp , -1 , sizeof(dp));
for(int i = 1 ; i <= n ; ++ i){
for(int j = sum ; j >= 0 ; -- j){
if(dp[j] != -1){
dp[j + c[i]] = max(dp[j + c[i]] , dp[j] + h[i]);
}
}
dp[c[i]] = max(dp[c[i]] , h[i]);
}
ll ans = 0;
for(int i = 1 ; i <= sum ; ++ i){
if(dp[i] != -1)
ans = max(ans , (long long)dp[i] * (ll)dp[i] - (ll)dp[i] * (ll)i - (ll)i * (ll)i);
}
printf("%lld\n" , ans);
}
return 0;
}
J Knuth-Morris-Pratt Algorithm
题意
查找给定字符串s中字符串“ cat”和“ dog”的出现总数。
题解
由于字符串长度<1e3 且 T <=30,所以直接模拟就可以了。
题目包括题面里说KMP算法,被迷惑了,所以队友写了kmp板子
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while(T--) {
string s;
cin >> s;
int ans = 0;
for(int i = 0; i <= s.length() - 3; i++) {
if(s[i] == 'c' && s[i + 1] == 'a' && s[i + 2] == 't') ans++;
if(s[i] == 'd' && s[i + 1] == 'o' && s[i + 2] == 'g') ans++;
}
printf("%d\n", ans);
}
}
//KMP的算法
#include <cstdio>
#include <cstring>
#include <algorithm>
#define INF 0x3f3f3f3f
#define N 1000005
typedef unsigned long long ll;
using namespace std;
char ans[N];
int nxt[N];
void get_next(char *T) {
nxt[0] = -1;
int i = 0, j = -1;
int len = strlen(T);
while(i < len) {
if(j == -1 || T[i] == T[j])
nxt[++i] = ++j;
else
j = nxt[j];
}
}
int KMP(char* S, char* T) {//返回S中T的个数
get_next(T);
int res = 0;
int len1 = strlen(T);
int len2 = strlen(S);
int i = 0, j = 0; //i指向模式串T,j指向主串S
while(j < len2) {
if(T[i] == S[j]) {
i++;
j++;
if(i == len1) {
//return j - i + 1;
res++;
}
}
else {
i = nxt[i];
if(i == -1) {
j++;
i++;
}
}
}
return res;
}
char s1[5] = {"cat"}, s2[5] = {"dog"};
char str[N];
int main() {
int T;
scanf("%d", &T);
while(T--) {
scanf("%s", str);
ll ans = KMP(str, s1);
ans += KMP(str, s2);
printf("%lld\n", ans);
}
return 0;
}