A.小 A 的点面论
题目大意:
输出与两个向量同时垂直的向量
注意:所得结果需为非零向量!
思路:
1、数据很小,直接暴力求解
两向量垂直:两向量的数量积为0
a
⋅
b
=
a
x
b
x
+
a
y
b
y
+
a
z
b
z
a\cdot b = a_xb_x+ a_yb_y+a_zb_z
a⋅b=axbx+ayby+azbz
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
const ll mod=1000000007;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
int main(){
int x1,y1,z1,x2,y2,z2;
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
for(int i=-200;i<=200;i++){
for(int j=-200;j<=200;j++){
for(int k=-200;k<=200;k++){
int a=x1*i+y1*j+z1*k;
int b=x2*i+y2*j+z2*k;
// cout<<i<<" "<<j<<" "<<k<<endl;
if(i==0&&j==0&&k==0) continue;//是否为零向量
if(a==0&&b==0){
printf("%d %d %d\n",i,j,k);
return 0;
}
}
}
}
return 0;
}
2、两向量的叉乘(向量积)即为答案
a
×
b
=
(
a
y
b
z
−
a
z
b
y
)
+
(
a
z
b
x
−
a
x
b
z
)
+
(
a
x
b
y
−
a
y
b
x
)
a\times b = (a_yb_z-a_zb_y)+(a_zb_x-a_xb_z)+(a_xb_y-a_yb_x)
a×b=(aybz−azby)+(azbx−axbz)+(axby−aybx)
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
int main(){
int x1,y1,z1,x2,y2,z2;
scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
int x,y,z;
x=y1*z2-z1*y2;
y=z1*x2-x1*z2;
z=x1*y2-y1*x2;
printf("%d %d %d\n",x,y,z);
return 0;
}
C. 小 A 的期末考试
题目大意:
给出n个人的成绩和小A的学号,如果小A的成绩小于60分则将其改成60分,如果除了小A之外有人的成绩大于等于平均分(按所有人初始成绩计算),小 A 会把他的成绩改低 2 分,但不会低于 0 分。
给出每个人被修改后的成绩。
思路:模拟
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
int a[maxn];
int main(){
int n,m;
scanf("%d%d",&n,&m);
double sum=0;
for(int i=1;i<=n;i++){
int id,grade;
scanf("%d%d",&id,&grade);
sum+=grade;
a[id]=grade;
}
sum/=n;
for(int i=1;i<=n;i++){
if(i==m&&a[i]<60) a[i]=60;
else if(i!=m&&a[i]>=sum){
a[i]-=2;
if(a[i]<0) a[i]=0;
}
printf("%d",a[i]);
if(i==n) printf("\n");
else printf(" ");
}
return 0;
}
E. Zztrans 的庄园
题目大意:
一共五种鱼,每种鱼对应不同的豆子数。
每次给出鱼塘里鱼的数量和钓鱼的次数
然后给出能钓到每种鱼的概率,求期望收益多少豆子。
思路:
因为钓到n条鱼的总概率为1,所以每一次钓鱼都必定会钓到鱼,不会落空。而且每一次钓鱼的结果都是独立的,所以只要算出钓一次鱼能收获的豆子数,最后乘以钓鱼次数即可。
期望定义式:
E
(
X
)
=
∑
i
=
1
n
p
i
×
x
i
E(X)=\sum_{i=1}^np_i\times x_i
E(X)=i=1∑npi×xi
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=3e5+10;
const ll mod=1000000007;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
int a[maxn];
double b[maxn];
int main(){
int n,k;
scanf("%d%d",&n,&k);
getchar();
double ans=0;
map<char,int>mp;
mp['D']=16;mp['C']=24;mp['B']=54;mp['A']=80;mp['S']=10000;
for(int i=0;i<n;i++){
char ch;
scanf("%c %lf",&ch,&b[i]);
a[i]=mp[ch];
getchar();//注意每次吸收换行!!
}
for(int i=0;i<n;i++){
ans+=a[i]*b[i];
}
printf("%.6lf\n",(ans-23)*k);
return 0;
}
G. 鸡哥的雕像
题目大意:
给出n个数, a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an
第i个位置输出:除 a i a_i ai以外的数字的乘积对998244353 取模后的结果。
思路:
1、大数模拟:会T
2、边取模边乘,再除以相应数:答案改变
3、前缀乘+后缀乘
去除
a
i
a_i
ai之后,其实将所有数分成了两个部分:
a
i
a_i
ai前面所有数字的乘积、
a
i
a_i
ai后面所有数字的乘积
预处理出前缀乘和后缀乘,即可用O(n)的复杂度求解
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
ll a[maxn];
ll b[maxn];
int x[maxn];
int main(){
int n;
scanf("%d",&n);
a[0]=1;
for(int i=1;i<=n;i++){//前缀乘
scanf("%d",&x[i]);
if(i==1) a[i]=x[i];
else a[i]=(a[i-1]*x[i])%mod;
}
b[n+1]=1;
for(int i=n;i>=1;i--){//后缀乘
if(i==n) b[i]=x[i];
else b[i]=(b[i+1]*x[i])%mod;
}
for(int i=1;i<=n;i++){
ll ans=(a[i-1]%mod*(b[i+1]%mod))%mod;
printf("%lld",ans);
if(i==n) printf("\n");
else printf(" ");
}
return 0;
}
4、逆元
利用乘法取模性质:
(
a
∗
b
)
%
m
o
d
=
(
(
a
%
m
o
d
)
∗
(
b
%
m
o
d
)
)
%
m
o
d
(a*b)\%mod=((a\%mod)*(b\%mod))\%mod
(a∗b)%mod=((a%mod)∗(b%mod))%mod
又因为本题mod=998244353 <1e9
所以可以进一步优化解法:
当出现多于两个mod时,取模后的结果一定全为0
若只有一个mod,那只有去除这个mod时,取模后的结果不为0,否则全为0
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
int x[maxn];
ll ksm(ll a,ll b){
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans%mod;
}
int main(){
int n;
scanf("%d",&n);
ll sum=1;
int cnt=0;
for(int i=1;i<=n;i++){
scanf("%d",&x[i]);
if(x[i]==mod) cnt++;
else sum=(sum*x[i])%mod;
}
if(cnt>=2){
for(int i=1;i<=n;i++){
printf("0");
if(i==n) printf("\n");
else printf(" ");
}
}
else if(cnt==1){
for(int i=1;i<=n;i++){
if(x[i]==mod) printf("%lld",sum);
else printf("0");
if(i==n) printf("\n");
else printf(" ");
}
}
else{
for(int i=1;i<=n;i++){
ll ans=(sum*ksm(x[i],mod-2))%mod;
printf("%lld",ans);
if(i==n) printf("\n");
else printf(" ");
}
}
return 0;
}
J. Alice and Bob-1
题目大意:
n张卡片,每张卡片都有一个数值。Alice和Bob轮流交替取卡片,直到取完。
每个人手中卡片的价值是所取得的卡片数值和的绝对值。
A = ∣ ∑ j = 1 k a j ∣ A=|\sum_{j=1}^ka_j| A=∣∑j=1kaj∣
B = ∣ ∑ i = 1 n a i − ∑ j = 1 k a j ∣ B=|\sum_{i=1}^na_i-\sum_{j=1}^ka_j| B=∣∑i=1nai−∑j=1kaj∣
Alice想让她取得的卡片的价值相比于Bob所取得的尽可能大,而Bob不想被Alice拉开差距,即:
Alice希望 A − B A-B A−B尽可能大,而Bob希望 A − B A-B A−B尽可能小。
两人均采取最优策略,求最终 A − B A-B A−B等于多少。
思路:
最优策略:
Alice每次都拿当前数值最大的卡片
Bob每次都拿当前第二大的卡片
但要注意负数的影响,所以需要从大到小取一次,从小到大取一次,然后Alice取两次的最大值,Bob取两次的最小值。
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
ll a[maxn];
int main(){
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld",&a[i]);
}
sort(a,a+n);
ll A1=0,A2=0,B1=0,B2=0;
for(int i=n-1;i>=0;i-=2){
A1+=a[i];
B1+=a[i-1];
}
for(int i=0;i<n;i+=2){
A2+=a[i];
B2+=a[i+1];
}
//cout<<A1<<" "<<A2<<" "<<B1<<" "<<B2<<endl;
A1=max(abs(A1),abs(A2)),B1=min(abs(B1),abs(B2));
printf("%lld\n",A1-B1);
return 0;
}
D. Zztrans 的班级合照
题目大意:
已知每个人身高从低到高排序后的排名(身高相同的人,排名也相同)
现需按如下要求排队:
排成人数相同的两排,每排从左到右身高都不递减,且第二排的同学的身高不低于第一排对应位置同学的身高。
求有多少种排队的方案,输出方案总数对 998244353取模后的结果。
思路:
1、求方案数,一般会用dp
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示已经排好前i个人,且第一行比第二行多j个人的方案数
2、对身高相同的人的处理:缩点
身高一样,排队的方案数取决于相同身高的人数有多少,试想其他人都已经排好,只剩下x个身高相同的人还没有排队,则这x个人排队的方案数为:
x
!
x!
x!
3、状态转移方程:
当前状态:
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]
设当前身高相同的人的数量为num
上一状态:
假设当前状态第一行有
x
+
j
x+j
x+j个人,第二行则有x个人,若当前状态是在上一状态的基础之上往第一行再排k个人,往第二行再排
n
u
m
−
k
num-k
num−k个人得到的,那上一状态第一行有
x
+
j
−
k
x+j-k
x+j−k个人,第二行有
x
−
(
n
u
m
−
k
)
x-(num-k)
x−(num−k)个人;则上一状态第一行人数比第二行多
x
+
j
−
k
−
(
x
−
(
n
u
m
−
k
)
)
=
j
+
n
u
m
−
2
k
x+j-k-(x-(num-k))=j+num-2k
x+j−k−(x−(num−k))=j+num−2k个人,
即上一状态为:
d
p
[
i
−
1
]
[
j
+
n
u
m
−
2
k
]
dp[i-1][j+num-2k]
dp[i−1][j+num−2k]
在上一状态再排num个身高相同的人的总方案数即为
d
p
[
i
−
1
]
[
j
+
n
u
m
−
2
k
]
∗
n
u
m
!
dp[i-1][j+num-2k]*num!
dp[i−1][j+num−2k]∗num!
但由于这num个人的分配方式不止一种(k的取值不止一种),所以需要将k从0到num进行遍历,将所有可能的方案都算上。
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
int a[maxn];
int vis[maxn];
ll dp[maxn][maxn];
ll f[maxn];
void init(){
f[1]=1;
for(int i=2;i<=5005;i++){
f[i]=(f[i-1]*i)%mod;
}
}
int main(){
int n;
cin>>n;
init();
for(int i=1;i<=n;i++){
cin>>a[i];
vis[a[i]]++;
}
sort(a+1,a+n+1);
int cnt=unique(a+1,a+n+1)-(a+1);//去重(将相同身高的人,缩成一个点)
dp[0][0]=1;//已排好0个人,且第一行比第二行多0个人的方案数为1
for(int i=1;i<=cnt;i++){
int num=vis[a[i]];
for(int j=0;j<=n;j++){
for(int k=0;k<=num;k++){
int l=j+num-2*k;
if(l<0) break;
dp[i][j]=(dp[i][j]+(dp[i-1][l]*f[num])%mod)%mod;
}
}
}
cout<<dp[cnt][0]<<endl;
return 0;
}
B. 小 A 的卡牌游戏
#include<bits/stdc++.h>
#define pb push_back
#define mpi make_pair
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn=1e4+10;
const ll mod=998244353;
const int INF=0x3f3f3f3f;
typedef pair<int,int> P;
typedef unsigned long long ull;
inline ll lowbit(ll x){return x&(-x);}
ll dp[maxn][maxn];
struct card{
int a,b,c;
bool operator <(const card&y) const{
if(b-a == y.b-y.a) return c>y.c;
return b-a>y.b-y.a;
}
}p[maxn];
int main(){
int n,A,B,C;
scanf("%d%d%d%d",&n,&A,&B,&C);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
}
sort(p+1,p+n+1);
for(int i = 0; i <= n; i++)
for(int j = i+1; j <= C; j++)
dp[i][j] = -1e9;
for(int i=1;i<=n;i++){
for(int j=0;j<=min(C,i);j++){
if(j) dp[i][j]=max(dp[i][j],dp[i-1][j-1]+p[i].c);
if(i-j<=B) dp[i][j]=max(dp[i][j],dp[i-1][j]+p[i].b);
else dp[i][j]=max(dp[i][j],dp[i-1][j]+p[i].a);
}
}
cout<<dp[n][C]<<endl;
return 0;
}