颜色共有七种,给定 n ( n ≤ 100 ) n(n≤100) n(n≤100) 个颜色,问七种颜色中哪些没有出现。
开一个大小为 7 7 7 的数组,分别统计七种颜色出现次数,最后看看哪些出现次数为 0 0 0 即可。
#include "bits/stdc++.h"
using namespace std;
int main() {
int n;
string s;
while(cin>>n) {
vector<int> cnt(7,0);
for(int i=1; i<=n; ++i) {
cin>>s;
if(s[0]=='r') cnt[0]++;
else if(s[0]=='o') cnt[1]++;
else if(s[0]=='y') cnt[2]++;
else if(s[0]=='g') cnt[3]++;
else if(s[0]=='c') cnt[4]++;
else if(s[0]=='b') cnt[5]++;
else if(s[0]=='p') cnt[6]++;
}
vector<char> ans;
for(int i=0; i<7; ++i) if(cnt[i]==0) {
ans.push_back(char('A'+i));
}
cout<<int(ans.size())<<'\n';
for(char p: ans) cout<<p<<'\n';
}
}
给定 n ( n ≤ 1 e 5 ) n(n≤1e5) n(n≤1e5) 个整数数对 ( a , b ) ( 0 ≤ a , b ≤ 1 e 9 ) (a,b)(0≤a,b≤1e9) (a,b)(0≤a,b≤1e9),有一个长度也为 n n n 的数组。
若将某个数对放在数组的第 i i i 个位置上,则其价值为: a ∗ ( i − 1 ) + b ∗ ( n − i ) a*(i-1)+b*(n-i) a∗(i−1)+b∗(n−i)。
求将这些数对分配在数组上后所有价值之和的最小值。
这是一种常见的考察排序、贪心的题目。
我们需要的就是给这些数对排个序,而排序就得知道两个数对的“大小关系”,因此我们来考察一下两个数对:
令 a 1 , b 1 a_1,b_1 a1,b1 在 i i i 位置, a 2 , b 2 a_2,b_2 a2,b2 在 j j j 位置,不妨假设 i < j i
若: a 1 ∗ ( i − 1 ) + b 1 ∗ ( n − i ) + a 2 ∗ ( j − 1 ) + b 2 ∗ ( n − j ) > a 1 ∗ ( j − 1 ) + b 1 ∗ ( n − j ) + a 2 ∗ ( i − 1 ) + b 2 ∗ ( n − i ) a_1*(i-1)+b_1*(n-i)+a_2*(j-1)+b_2*(n-j)>a_1*(j-1)+b_1*(n-j)+a_2*(i-1)+b_2*(n-i) a1∗(i−1)+b1∗(n−i)+a2∗(j−1)+b2∗(n−j)>a1∗(j−1)+b1∗(n−j)+a2∗(i−1)+b2∗(n−i)
则: ( a 1 − a 2 ) ∗ ( i − 1 ) + ( b 1 − b 2 ) ∗ ( n − i ) > ( a 1 − a 2 ) ∗ ( j − 1 ) + ( b 1 − b 2 ) ∗ ( n − j ) (a_1-a_2)*(i-1)+(b_1-b_2)*(n-i)>(a_1-a_2)*(j-1)+(b_1-b2)*(n-j) (a1−a2)∗(i−1)+(b1−b2)∗(n−i)>(a1−a2)∗(j−1)+(b1−b2)∗(n−j)
则: ( a 1 − a 2 ) ∗ ( i − j ) > ( b 1 − b 2 ) ∗ ( i − j ) (a_1-a_2)*(i-j)>(b_1-b_2)*(i-j) (a1−a2)∗(i−j)>(b1−b2)∗(i−j)
则: a 1 − b 1 < a 2 − b 2 a_1-b_1
上述推导表明若处于靠前的 i i i 位置的数对需要和靠后的 j j j 位置的数对发生交换,则应该满足前者的 a − b a-b a−b 较小。
也就是说: a − b a-b a−b 较大的数对应该放得更靠前!
这样,我们就可以设计排序函数了,通过 a − b a-b a−b 的大小来决定两个数对的优先关系。
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
struct Pair{
int a, b;
friend bool operator < (const Pair &A, const Pair &B) {
return A.a-A.b>B.a-B.b;
}
}p[maxn];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int n;
while(cin>>n) {
for(int i=1; i<=n; ++i) {
cin>>p[i].a>>p[i].b;
}
sort(p+1,p+1+n); //sort就完事
ll ans=0;
for(int i=1; i<=n; ++i) {
ans+=ll(i-1)*p[i].a+ll(n-i)*p[i].b; //小心爆int啦
}
cout<<ans<<'\n';
}
}
有一个 n ∗ m ( n , m ≤ 5000 ) n*m(n,m≤5000) n∗m(n,m≤5000) 的矩形,PIPI每次只能从矩形的某一个点向右走或向下走。
问从 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 到 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 共有多少种走法?(答案对 1 e 9 + 7 1e9+7 1e9+7取模)
难点:多组数据 + 每组数据 q ( q ≤ 5000 ) q(q≤5000) q(q≤5000) 个询问,因此总询问次数可能非常多!
由于询问次数非常多,那我们能提前处理好所有可能的询问就好了。
考虑 ( x 1 , y 1 ) (x_1,y_1) (x1,y1) 到 ( x 2 , y 2 ) (x_2,y_2) (x2,y2) 之间的所有方格构成了一个矩形,并且此矩形在原 n ∗ m n*m n∗m 矩形中位置不影响方案数,只有这个矩形的尺寸决定方案数。
因此,我们预处理 n m a x ∗ n m a x ( n m a x = 5000 ) n_{max}*n_{max}(n_{max}=5000) nmax∗nmax(nmax=5000) 的矩形即可,预处理:
设: w a y s [ i ] [ j ] ways[i][j] ways[i][j]表示从 ( 1 , 1 ) (1,1) (1,1) 走到 ( i , j ) (i,j) (i,j)处的方案数。
则: w a y s [ i ] [ j ] = w a y s [ i − 1 ] [ j ] + w a y s [ i ] [ j − 1 ] ways[i][j]=ways[i-1][j]+ways[i][j-1] ways[i][j]=ways[i−1][j]+ways[i][j−1]
处理好后,对于每次的询问可以直接 O ( 1 ) O(1) O(1) 回答: w a y s [ x 2 − x 1 + 1 ] [ y 2 − y 1 + 1 ] ways[x2-x1+1][y2-y1+1] ways[x2−x1+1][y2−y1+1]
时间复杂度: O ( n ∗ n + T ∗ q ) O(n*n + T * q) O(n∗n+T∗q),空间复杂度: O ( n ∗ n ) O(n*n) O(n∗n)
(PS:尽量不要使用cin和cout,否则输入输出速度太慢,自行优化)
#include "bits/stdc++.h"
using namespace std;
const int maxn = 5e3+7;
const int mod = 1e9+7;
int ways[maxn][maxn];
int main() {
ways[1][0]=1; //一个假想的入口(1,0),方便对ways[1][1]进行赋值
for(int i=1; i<maxn; ++i) {
for(int j=1; j<maxn; ++j) {
ways[i][j]=(ways[i-1][j]+ways[i][j-1])%mod;
}
}
int n, m, q;
ios::sync_with_stdio(false); cin.tie(0); //这里通过采用取消输入输出同步的方式加快读入
while(cin>>n>>m>>q) {
while(q--) {
int x1, y1, x2, y2;
cin>>x1>>y1>>x2>>y2;
cout<<ways[x2-x1+1][y2-y1+1]<<'\n'; //不要cout<
}
}
}
有 m m m 根木棍, m = n ∗ k ( n , k ≤ 1 e 5 ) m=n*k(n,k≤1e5) m=n∗k(n,k≤1e5) , n n n 个桶,每个桶由 k k k 根木棍构成,桶的容量由最短的木棍长度决定,桶的底面积为 1 1 1,木棍长度不大于 1 e 9 1e9 1e9。
现要求最大的桶和最小的桶容量差小于等于 L L L,问 n n n 个桶的最大容量和。
如果无法满足组成 n n n 个桶,输出 0 0 0。
由于桶的容量由构成它的最短木棍决定,因此我们希望那些决定桶的容量的木棍就尽可能长。
在不考虑 L L L 的情况下,我们只需要将所有木棍拍个序,然后从较大的到较小的依次选择木棍,每有 k k k 根木棍,我们就拿他们构建一个桶。
显然,这样构建的 n n n 个桶容量都是尽可能大了。
然后再来考虑 L L L 这个限制条件,由于所有木棍最短的那根一定决定了最小容量桶的容量,因此,我们只要最大的桶不要用大于 a m i n + L a_{min}+L amin+L 的木棍决定它即可。
最终,我们仍然只需要从大到小选择木棍,但一定要从不大于 a m i n + L a_{min}+L amin+L 的地方开始构建桶;同理,若这样的方法最后导致有些木棍没有参与构建桶子,那么就输出 0 0 0 ,具体见代码。
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
int a[maxn];
int main() {
int n, k, L;
scanf("%d%d%d", &n, &k, &L);
int N=n*k;
for(int i=1; i<=N; ++i) scanf("%d", &a[i]);
sort(a+1,a+1+N);
int max_position=upper_bound(a+1,a+1+N,a[1]+L)-a; //最大桶不能取到的第一个地方
ll ans=0;
int cur_num=0; //cur_num记录有多少木棍等待使用
for(int i=N; i; --i) {
cur_num++;
if(i<max_position&&cur_num>=k) {
ans+=a[i]; //用a[i]决定这个桶的容量
cur_num-=k; //使用k根木棍
}
}
if(cur_num>0) printf("0\n"); //说明还有木棍没用上,那么就不能组成n个桶了
else printf("%lld\n", ans);
}
给定一个常数 c c c,若一个数组长度为 l l l,则它的特征值为除去最小的 l / c l/c l/c (向下取整)外的所有元素之和。
给定一个长度为 n ( n ≤ 1 e 6 ) n(n≤1e6) n(n≤1e6) 的数组和常数 c ( c ≤ 1 e 6 ) c(c≤1e6) c(c≤1e6),数组的元素为不大于 1 e 9 1e9 1e9的自然数,求一个最优的划分,使得所有子数组特征值之和最小。
首先,特征值之和最小意味着未参与贡献的元素之和最大。
本题数据非常大( 1 e 6 1e6 1e6级别),意味着只能使用 O ( n ) O(n) O(n) 或 O ( l o g 2 n ) O(log_2n) O(log2n) 的方法,因此思考的方向就少了很多。
考虑某种划分中出现了长度为 l l l的子数组:
观察上述分析可知,划分过程中所有子数组长度仅为 1 1 1 或 c c c 就可以得到最优解,大方向确定后只剩下如何得到最优解。
考虑 O ( n ) O(n) O(n) 的做一次动态规划,令 d p [ i ] dp[i] dp[i] 表示前 i i i 个元素中不参与贡献元素之和最大值,则转移方程为:
d p [ i ] = m a x ( d p [ i − 1 ] , d p [ i − c ] + m i n ( a [ i − c + 1 … i ] ) dp[i]=max(dp[i-1],dp[i-c]+min(a[i-c+1\dots i]) dp[i]=max(dp[i−1],dp[i−c]+min(a[i−c+1…i])
m i n ( a [ i − c … i ] ) min(a[i-c\dots i]) min(a[i−c…i]) 可通过维护一个大小始终为 c c c 的可重集或滑动窗口实现。
这样,得到最大不参与贡献元素和后,最小参与贡献元素和也就出来了:
a n s = s u m − d p [ n ] ans=sum-dp[n] ans=sum−dp[n]
时间复杂度: O ( n l o g 2 c ) O(nlog_2c) O(nlog2c)
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int maxn = 1e6+7;
int n, c;
int a[maxn];
ll dp[maxn];
int main() {
scanf("%d%d", &n, &c);
multiset<int> s; //要使用可重集哦,不然有些元素可能会丢掉
ll sum=0;
for(int i=1; i<=n; ++i) {
scanf("%d", &a[i]);
dp[i]=dp[i-1];
s.insert(a[i]);
if(i>c) s.erase(s.find(a[i-c])); //总是保证s中只有c个元素
if(i>=c) {
dp[i]=max(dp[i],dp[i-c]+(*s.begin()));
}
sum+=a[i];
}
printf("%lld\n", sum-dp[n]);
}