A:
题意:
给一堆单词(用’ \space ’分开),问所有单词中单个单词大写字母最多有多少\
题解:
没什么好说的了主要是读懂题意
代码:
#include<bits/stdc++.h>
using namespace std;
int n;char ch[222];
signed main(){
scanf("%d",&n);int ans = 0;
while(scanf("%s",ch + 1) != EOF){
int cnt = 0;for(int i = 1;i <= strlen(ch + 1);i++){if('A' <= ch[i] && ch[i] <= 'Z')cnt++;}
ans = max(ans,cnt);
}
printf("%d\n",ans);
return 0;
}
B:
题意:
Berland之旗是满足以下条件的 n × m n \times m n×m 矩形区域:
-
旗中包含三种颜色,相应地以字母“R”, “G”和“B”表示。
-
旗中包含三个“长条”,他们的长度和宽度相等(长条1的长度等于长条2的长度,也等于长条3的长度,宽度类似),并且互相平行,同时还平行于旗子的边缘。每个“长条”仅有一种颜色。
-
每个颜色仅能在一个“长条”中出现。
现在给定由“R”, “G”和“B”构成的 n × m n \times m n×m 矩形区域。请判断它是否是一个正确的Berland之旗,是则输出 “YES”,否则输出"NO"。
题解:
所谓的??之旗就是让你找一个 n n n% 3 = = 0 3==0 3==0 或者 m m m% 3 = = 0 3==0 3==0,然后判断一下是不是分成三部分(想象一下用刀沿着n或m平均切三刀)每一部分颜色都相同且不重复
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 110;
int n, m;char ch[maxn][maxn];int a[maxn][maxn];
bool book[4];
bool check(int x,bool mod){
if(mod){
int col = a[1][m / 3 * x + 1];if(book[col])return 0;book[col] = 1;
for(int i = 1;i <= n;i++){
for(int j = m / 3 * x + 1;j <= m / 3 * (x + 1);j++){
// printf("%d %d\n",i,j);
if(a[i][j] != col)return false;
}
}
return true;
}
else{
int col = a[n / 3 * x + 1][1];if(book[col])return 0;book[col] = 1;
for(int i = 1;i <= m;i++){
for(int j = n / 3 * x + 1;j <= n / 3 * (x + 1);j++){
if(a[j][i] != col)return false;
}
}
return true;
}
}
signed main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++){
scanf("%s",ch[i] + 1);
for(int j = 1;j <= m;j++)
a[i][j] = (ch[i][j] == 'R' ? 1 : (ch[i][j] == 'G' ? 2 : 3));
}
bool ans = 0;
if(m % 3 == 0){
bool res = 1;memset(book,0,sizeof(book));
for(int i = 0;i <= 2;i++)if(!check(i,1)){res = 0;break;}
ans |= res;
}
if(n % 3 == 0){
bool res = 1;memset(book,0,sizeof(book));
for(int i = 0;i <= 2;i++)if(!check(i,0)){res = 0;break;}
ans |= res;
}
puts(ans ? "YES" : "NO");
return 0;
}
C:
题意:
给一个 a ∗ b a*b a∗b 的大矩形和 n n n 个 x i ∗ y i x_i*y_i xi∗yi 的小矩形(可旋转 90 ° 90° 90° ),要求找两个小矩形塞进大矩形中并且面积之和最大
题解:
放矩形的时候让一个的左上角顶在 ( 1 , 1 ) (1,1) (1,1) ,另一个的右下角顶在 ( a , b ) (a,b) (a,b) ,判断能不能放下就好了
代码:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 110;
int x[maxn], y[maxn];
int n, a, b;
bool check(int xi,int yi,int xj,int yj){
if(xi > a || xj > a || yi > b || yj > b)return false;
if(xi + xj > a && yi + yj > b)return false;
return true;
}
signed main(){
int ans = 0;n = read();a = read(); b = read();
for(int i = 1;i <= n;i++)x[i] = read(), y[i] = read();
for(int i = 1;i <= n;i++){
for(int j = 1;j <= n;j++){
if(i == j)continue;
if(check(x[i],y[i],x[j],y[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
if(check(y[i],x[i],x[j],y[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
if(check(x[i],y[i],y[j],x[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
if(check(y[i],x[i],y[j],x[j]))ans = max(ans,x[i] * y[i] + x[j] * y[j]);
}
}
printf("%d\n",ans);
return 0;
}
D:
题意:
给你n个数,选k个数相乘使得结果的后缀0最多
题解:
幼儿园大班芝士可知后缀0由质因子中的2和5决定
于是乎定义
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k 表示取到第
i
i
i 个数,已经取了
j
j
j 个数,
5
5
5 的质因子有
k
k
k 个时
2
2
2 的质因子最大值
然后
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k =
m
i
n
(
d
p
i
−
1
,
j
,
k
,
d
p
i
−
1
,
j
−
1
,
k
−
c
n
t
5
i
+
c
n
t
2
i
)
min(dp_{i-1,j,k},dp_{i-1,j-1,k-cnt5_i}+cnt2_i)
min(dpi−1,j,k,dpi−1,j−1,k−cnt5i+cnt2i)
初始条件
d
p
0
,
0
,
0
=
0
dp_{0,0,0}=0
dp0,0,0=0 其余为
−
I
N
F
-INF
−INF
然后显然发现这个是01背包可以把i维度优化掉
然后就没有然后了
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 210;
int n, k;int a[maxn], b[maxn];
int dp[maxn][12810];//dp[i][j][k] = 当前到第i个数,选了j个数,5的因数为k个时2的因数最大值
signed main(){
n = read();k = read();int x = 0;
for(int i = 1;i <= n;i++){
x = read();if(!x)continue;
while(x % 2 == 0){a[i]++;x /= 2;}
while(x % 5 == 0){b[i]++;x /= 5;}
}
memset(dp,~0x3f,sizeof(dp)); dp[0][0] = 0;
for(int i = 1;i <= n;i++)
for(int j = k;j >= 1;j--)
for(int l = 12800;l >= b[i];l--)
dp[j][l] = max(dp[j][l],dp[j - 1][l - b[i]] + a[i]);
int ans = 0;
for(int i = 0;i <= 12800;i++){ans = max(ans,min(i,dp[k][i]));}
printf("%lld\n",ans);
return 0;
}
E:
题意:
定义一个函数
f
(
n
,
m
)
=
{
0
,
(
m
=
0
)
1
+
f
(
n
,
m
−
g
c
d
(
n
,
m
)
)
,
(
m
≠
0
)
f(n,m) = \begin{cases} 0,\,\,(m=0)\\ 1+f(n,m-gcd(n,m)),\,\,(m\neq0)\\ \end{cases}
f(n,m)={0,(m=0)1+f(n,m−gcd(n,m)),(m=0)
然后给出
n
n
n和
m
m
m,求
f
(
n
,
m
)
f(n,m)
f(n,m)
题解:
首先有一个推论
f
(
n
,
m
)
=
f
(
n
g
c
d
(
n
,
m
)
,
m
g
c
d
(
n
,
m
)
)
f(n,m)=f(\frac{n}{gcd(n,m)},\frac{m}{gcd(n,m)})
f(n,m)=f(gcd(n,m)n,gcd(n,m)m)
然后问题就变成了每次求最大的
x
<
=
m
x<=m
x<=m使得
x
∣
n
x|n
x∣n然后
f
(
n
,
m
)
=
x
+
f
(
n
,
x
)
f(n,m)=x+f(n,x)
f(n,m)=x+f(n,x)
这个好办,只需要把n的质因数都找出来(
O
(
log
2
n
)
)
O(\log_2n))
O(log2n))的
然后每次更新时只需要暴力枚举找到
m
a
x
(
m
max(m
max(m%
i
)
i)
i),然后x就是前面的max值
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int a, b;
const int maxn = 1e6 + 10;
bool book[maxn];int prime[maxn], cnt;
int x[maxn], p[maxn], tot;
int gcd(int x,int y){return y == 0 ? x : gcd(y,x % y);}
int f(int n,int m){
int ans = 0;
while(1){
int mx = 0, pos = 0;
for(int i = 1;i <= tot && x[i] <= m;i++)
if(p[i] && (m / x[i] * x[i] > mx))mx = m / x[i] * x[i], pos = i;
ans += m - mx;m = mx;
if(!m)return ans;
// if(m == 1){return ans + 1;}
--p[pos];n /= x[pos]; m /= x[pos];
}
return -114514;
}
signed main(){
scanf("%lld%lld",&a,&b);
// book[1] = 1;int g = gcd(a, b);a /= g;b /= g;
for(int i = 2;i <= 1e6;i++){
if(!book[i]){prime[++cnt] = i;}
for(int j = 1;j <= cnt && i * prime[j] <= 1e6;j++){
book[i * prime[j]] = 1;
if(i % prime[j] == 0)break;
}
}
// for(int i = 1;i <= 10;i++)printf("prime[%lld] = %lld\n",i,prime[i]);
int tmp = a;
// tot++;x[tot] = 1;p[tot] = 1e18;
for(int i = 1;i <= cnt && tmp >= prime[i];i++){
if(tmp % prime[i] == 0){
tot++;x[tot] = prime[i];while(tmp % prime[i] == 0){tmp /= prime[i];p[tot]++;}
}
}
if(tmp != 1){tot++;x[tot] = tmp;p[tot] = 1;}
// printf("%lld\n",tot);
// for(int i = 1;i <= tot;i++)printf("x[%lld] = %lld,p[%lld] = %lld\n",i,x[i],i,p[i]);
printf("%lld\n",f(a,b));
return 0;
}
F:
题意:
给一个数组 a a a,每次操作让新的 a i a_i ai赋值为原来的 ∑ j = 1 i a j \sum_{j=1}^{i}a_j ∑j=1iaj,问最少多少次操作使得 ∃ i , a i > = k \exist i,a_i>=k ∃i,ai>=k
题解:
首先对于
n
=
=
2
n==2
n==2的情况可以
O
(
1
)
O(1)
O(1)的计算答案(手推一下柿子就好了),对于
n
>
10
n>10
n>10的情况可以暴力计算次数(由题解得最多计算410次),而对于
2
<
n
<
=
10
2<n<=10
2<n<=10的情况可以用二分答案+矩阵快速幂
细节:
- 原数组中的前导零无意义,直接删除
- 乘法需要用龟速乘并且大于 k k k的数字没有乘的必要直接等于 k k k即可
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f= 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 2e5 + 10;
int n, k;
int a[maxn], tmp[maxn];
inline int mul(int a,int b){
int res = 0;
while(b){
if(b & 1)res = res + a;
if(res > k)return k;
a = a + a;b >>= 1;a = min(k, a);
}
return res;
}
struct Matrix{
int a[11][11];
Matrix(){memset(a,0,sizeof(a));}
friend Matrix operator * (Matrix a,Matrix b){
Matrix ans;
for(int i = 1;i <= n;i++)
for(int t = 1;t <= n;t++)
for(int j = 1;j <= n;j++){
ans.a[i][j] += mul(a.a[i][t] , b.a[t][j]);
if(ans.a[i][j] > k)ans.a[i][j] = k;
}
return ans;
}
}A, B;
Matrix qpow(Matrix a,int x){
Matrix res = a;x--;
while(x){
if(x & 1){res = res * a;}
a = a * a;x >>= 1;
// printf("x= %lld\n",x);
}
return res;
}
bool check(int mid){
Matrix res = A * qpow(B,mid);
// puts("1111111111");
for(int i = 1;i <= n;i++){if(res.a[1][i] >= k)return true;}
return false;
}
signed main(){
// #ifndef ONLINE_JUDGE
// freopen("CF837F.in","r",stdin);
// #endif
n = read(); k = read();
for(int i = 1;i <= n;i++)a[i] = read();
int pos1 = 0, j = 1, book = 1;
for(int i = 1;i <= n;i++){if(a[i] >= k){puts("0");return 0;}if(!a[i] && book)pos1 = i;else book = 0;}
for(int i = pos1 + 1;i <= n;i++,j++){tmp[j] = a[i];}j--;
for(int i = 1;i <= j;i++)a[i] = tmp[i];n = j;
// printf("%lld\n",n);
// for(int i = 1;i <= n;i++){printf("%lld ",a[i]);}
if(n > 10){
int cnt = 0;
while(1){
tmp[0] = 0;cnt++;
for(int i = 1;i <= n;i++)tmp[i] = tmp[i - 1] + a[i];
for(int i = 1;i <= n;i++){
a[i] = tmp[i];
if(a[i] >= k){printf("%lld\n",cnt);return 0;}
}
}
}
else if(n == 2){
// if(a[2] >= k || a[1] >= k){puts("0");return 0;}
int ans = (k - a[2]) / a[1] - 3;
while(1){//精度修正
if(ans * a[1] + a[2] >= k){printf("%lld\n",ans);return 0;}
ans++;
}
}
else{
for(int i = 1;i <= n;i++){A.a[1][i] = a[i];}
for(int i = 1;i <= n;i++)
for(int j = n;j >= i;j--)
B.a[i][j] = 1;
int l = 1, r = 64356879284, mid = 0, ans = -1;
// printf("n = %lld",n);
while(l <= r){
// printf("l=%lld r=%lld\n",l,r);
mid = (r - l) / 2 + l;
// printf("mid=%lld\n",mid);
if(check(mid)){ans = mid;r = mid - 1;}
else l = mid + 1;
}
printf("%lld\n",ans);
}
return 0;
}
G:
题意:
给出n个分段函数形如
f
i
(
x
)
=
{
y
1
,
(
x
<
=
x
1
)
a
∗
x
+
b
,
(
x
1
<
x
<
=
x
2
)
y
2
,
(
x
>
x
2
)
f_i(x)={ \begin{cases} y_1,\,\,(x<=x_1)\\ a*x+b,\,\,(x_1<x<=x_2)\\ y_2,\,\,(x>x_2) \end{cases} }
fi(x)=⎩
⎨
⎧y1,(x<=x1)a∗x+b,(x1<x<=x2)y2,(x>x2)
现在给出
l
,
r
,
x
l,r,x
l,r,x,求
∑
i
=
l
r
f
i
(
x
)
\sum_{i=l}^rf_i(x)
∑i=lrfi(x),强制在线
题解:
首先先将原函数看作以下形式
f
i
(
x
)
=
{
0
∗
x
+
y
1
,
(
x
<
=
x
1
)
a
∗
x
+
b
,
(
x
1
<
x
<
=
x
2
)
0
∗
x
+
y
2
,
(
x
>
x
2
)
f_i(x)={ \begin{cases} 0*x+y_1,\,\,(x<=x_1)\\ a*x+b,\,\,(x_1<x<=x_2)\\ 0*x+y_2,\,\,(x>x_2) \end{cases} }
fi(x)=⎩
⎨
⎧0∗x+y1,(x<=x1)a∗x+b,(x1<x<=x2)0∗x+y2,(x>x2)
然后将所求柿子转化一下
∑
i
=
l
r
f
i
(
x
)
=
∑
i
=
l
r
a
i
∗
x
+
∑
i
=
l
r
b
i
\sum_{i=l}^rf_i(x)=\sum_{i=l}^ra_i*x+\sum_{i=l}^rb_i
∑i=lrfi(x)=∑i=lrai∗x+∑i=lrbi
\space
\space
\space
\space
\space
\space
\space
\space
\space
\space
=
∑
i
=
1
r
a
i
∗
x
+
∑
i
=
1
r
b
i
−
∑
i
=
1
l
−
1
a
i
∗
x
+
∑
i
=
1
l
−
1
b
i
=\sum_{i=1}^ra_i*x+\sum_{i=1}^rb_i-\sum_{i=1}^{l-1}a_i*x+\sum_{i=1}^{l-1}b_i
=∑i=1rai∗x+∑i=1rbi−∑i=1l−1ai∗x+∑i=1l−1bi
然后发现这玩应似乎可以可持久化主席树
然后就没啥了(那你还调了一下午)\
细节:
- 线段树数组范围能开多大就多大(
反正内存限制接近1GB)
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 75100, mod = 1e9;
int n, m;
int a[maxn][3], b[maxn][3], x[maxn][2];
struct Segment_Tree{
struct node{
int l, r;int a, b;
node(int a = 0,int b = 0,int l = 0,int r = 0):a(a),b(b),l(l),r(r){}
}d[maxn * 160];
int tot;
int newnode(int p){d[++tot] = d[p];return tot;}
void update(int &p,int l,int r,int s,int t,int a,int b){
p = newnode(p);
if(s <= l && r <= t){d[p].a += a;d[p].b += b;return;}
int mid = l + r >> 1;
if(s <= mid)update(d[p].l,l,mid,s,t,a,b);
if(mid < t)update(d[p].r,mid + 1,r,s,t,a,b);
}
int query(int p,int l,int r,int x){
if(!p)return 0;
int res = x * d[p].a + d[p].b;
if(l == r)return res;
int mid = l + r >> 1;
if(x <= mid)res += query(d[p].l,l,mid,x);
else res += query(d[p].r,mid + 1,r,x);
return res;
}
}tree;
int head[maxn << 2], sum[maxn];
signed main(){
n = read();int mx = 0;
for(int i = 1;i <= n;i++){
x[i][0] = read();x[i][1] = read();b[i][0] = read();
a[i][1] = read();b[i][1] = read();b[i][2] = read();
head[i] = head[i - 1];
tree.update(head[i],0,mod,0 ,x[i][0],a[i][0],b[i][0]);
tree.update(head[i],0,mod,x[i][0] + 1,x[i][1],a[i][1],b[i][1]);
tree.update(head[i],0,mod,x[i][1] + 1,mod ,a[i][2],b[i][2]);
sum[i] = sum[i - 1] + b[i][2];mx = max(mx,x[i][1] + 1);
}
m = read();int lastans = 0;
for(int i = 1;i <= m;i++){
int l = read(), r = read(), pos = (read() + lastans) % mod;
if(pos >= mx)printf("%lld\n",lastans = sum[r] - sum[l - 1]);
else printf("%lld\n",lastans = tree.query(head[r],0,mod,pos) - tree.query(head[l - 1],0,mod,pos));
}
return 0;
}