230226题解
A 数列
题目描述
给定一个长为
给出
输入格式
第一行两个整数
第二行
接下来
保证
输出格式
对于每个询问输出一行一个整数,表示答案。
样例 1
输入
5 3
6 11 2 5 5
5
20
0
输出
10
71
29
样例 2
输入
10 5
1000000000 314159265 271828182 141421356 161803398 0 777777777 255255255 536870912 998244353
555555555
321654987
1000000000
789456123
0
输出
3316905982
2811735560
5542639502
4275864946
4457360498
题解
十分简单得一道题
首先排序,方便用二分查找,因为操作是减一或加一,所以我们在数组大的那一边减一,小的那一边加一,
用前缀和数组
#include<bits/stdc++.h>
using namespace std;
int n,q,a[200010],maxn,minn = 0x7fffffff;
long long sum[200010];
int main(){
scanf("%d%d",&n,&q);
for(int i = 1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
for(int i = 1;i<=n;i++)
sum[i] = (long long)(sum[i-1]+a[i]);
for(int i = 1;i<=q;i++){
long long x;
scanf("%lld",&x);
int l = lower_bound(a+1,a+n+1,x)-a;
long long ans1 = x*(l-1)*1ll-sum[l-1];
long long ans2 = sum[n]-sum[l-1]-x*(n-l+1)*1ll;
printf("%lld\n",ans1+ans2);
}
return 0;
}
B 序列编号
题目描述
序列王国的国王小 A 想要给所有序列编号。具体来讲,他需要给每个长为
请你输出编号的方案数,模
输入格式
一行三个整数
保证
输出格式
输出一行一个整数,表示答案。
样例 1
输入
2 2 2
输出
16
题解
这个题目一看就是组合数学,但是我并不会
得出的式子应该是
证明如下:
对于每一个数列,每一个位置都有
那么对于每一个数列来说都有
对于每一个数列来说,都有
所以总共
然后我们可以看看数据范围,明显是快速幂过不去的,我们需要找一种
欧拉函数在这个情况下
扩展欧拉定理如下但好像对这道题没什么用
注意:我们不对
还有一点要注意的,在计算
基本上这些就是所有的要点了所有坑都被我踩了一遍了QAQ
#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
using namespace std;
ll n,k,m;
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll qpow(ll x,ll y,ll modd){
ll a = 1;
for(;y;y>>=1,x = (ll)x*x%modd)
if(y&1) a = (ll)a*x%modd;
return a;
}
int main(){
scanf("%lld%lld%lld",&n,&k,&m);
k%=(mod-1),m%=mod;
if(m==0){
puts("0");
return 0;
}
ll ans = qpow(k,n,mod-1);
ans = qpow(m,ans,mod);
printf("%lld",ans);
return 0;
}
C 最小生成树
题目描述
给定一个
请你回答
输入格式
第一行三个整数
接下来
接下来
保证
输出格式
对每个询问输出一行 Yes
或 No
表示询问的答案。
样例 1
输入
5 6 3
1 2 2
2 3 3
1 3 6
2 4 5
4 5 9
3 5 8
1 3 1
3 4 7
3 5 7
输出
Yes
No
Yes
样例 2
输入
2 3 2
1 2 100
1 2 1000000000
1 1 1
1 2 2
1 1 5
输出
Yes
No
题解
首先我们需要在原来的图上知道那些边被加入了最小生成树
再考虑询问,如果询问的边符合 kruskal 的要求,就输出 Yes
但明显是会炸时间的,所以我们只用跑一次 kruskal
离线下所有的询问,对于原图上的边才增加生成树中边的个数
对于询问则不改变生成树中边的个数,记录是否会被选到
#include<bits/stdc++.h>
using namespace std;
struct edge{
int u,v,w,id;
}e[500010];
int n,m,q,fa[200010],cnt;
bool a[200010];
bool cmp(edge a,edge b){
return a.w<b.w;
}
void add(int u,int v,int w,int flag){
e[++cnt].u = u;
e[cnt].v = v;
e[cnt].w = w;
e[cnt].id = flag;
}
int find_(int x){
return fa[x]==x?x:fa[x] = find_(fa[x]);
}
void kruskal(){
int k = n-1,i = 1;
while(k&&i<=cnt){
int u = find_(e[i].u),v = find_(e[i].v);
if(u!=v){
a[e[i].id] = true;
if(!e[i].id){
fa[u] = v;
k--;
}
}
i++;
}
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i<=n;i++)
fa[i] = i;
for(int i = 1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,0);
}
for(int i = 1;i<=q;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w,i);
}
sort(e+1,e+cnt+1,cmp);
kruskal();
for(int i = 1;i<=q;i++)
if(a[i]) puts("Yes");
else puts("No");
return 0;
}
D 等差数
题目描述
对于一个数,如果它的数码形成一个等差数列,那么我们称之为等差数。例如
现在请你找出大于等于
输入格式
一行一个整数
保证
输出格式
输出一行一个整数,表示答案。
样例 1
输入
152
输出
159
题解
容易知道一点,等差数在 鸽子当太久记不到数据了
那么我们只需要暴力枚举出每一个等差数即可,当然不可能是一个一个数枚举
我们可以从等差数每一位的差来入手,枚举完差值再枚举第一位的数字,再由第一位的数字推至每一位
最后用二分查找即可知道询问在多少位
#include<bits/stdc++.h>
using namespace std;
int main(){
long long x;
scanf("%lld",&x);
set<long long> st;
st.insert(0);
for(int i = -9;i<=9;i++){
for(int j = 1;j<=9;j++){
long long a = j;
st.insert(a);
int tmp = j;
while(true){
tmp+=i;
if(tmp<0||tmp>9){
break;
}
a = a*10+tmp;
st.insert(a);
if(a>=x){
break;
}
}
}
}
printf("%lld",*st.lower_bound(x));
return 0;
}
E 巧克力
题目描述
小 A 获得了长度为
具体来讲,小 A 有
现在,小 A 要通过如下方式将巧克力切成若干块:
选择一个长为
请你计算小 A 最少需要多少的代价才能把巧克力分给他的朋友们。
输入格式
第一行两个整数
第二行
保证
输出格式
输出一行一个数,表示最小需要的代价。
样例 1
输入
5 7
1 2 1 2 1
输出
16
题解
我们逆向思考一下这道题,把砍的过程换成拼的过程,那么就是每次将最小的两堆合并起来那么一定是最优
#include<bits/stdc++.h>
using namespace std;
long long ans,m,n,k;
priority_queue<long long,vector<long long>,greater<long long> >q;
int main(){
scanf("%lld%lld",&n,&m);
for(long long i = 1;i<=n;i++){
long long x;
scanf("%lld",&x);
q.push(x);
m-=x;
}
if(m) q.push(m);
while(q.size()>1){
long long tmp = q.top();q.pop();
long long cnt = q.top();q.pop();
ans+=tmp+cnt;
q.push(tmp+cnt);
}
printf("%lld",ans);
return 0;
}
F 选拔
题目描述
AT 省即将进行竞赛省队选拔。
今年 AT 省共有
AT 省共有
请你求出有多少种选出省队选手的方案。模 998244353。
输入格式
第一行两个数
接下来两行,每行
保证
输出格式
输出一行一个整数,表示答案。
样例 1
输入
4 2
2 4 3 1
2 1 4 3
输出
3
题解
我们先去掉一个限制条件,把 p 数组先排好序,那么就只用考虑 q 的大小了
这时候我们可以用 dp 来计算答案万恶之源来了
设计一个
至于赋初始值为什么是
至于遍历时要开到
#include<bits/stdc++.h>
#define mod 998244353
#define N 310
using namespace std;
int n,q,a[N],p[N];
long long f[N][N][N],ans;
int main(){
scanf("%d%d",&n,&q);
for(int i = 1;i<=n;i++)
scanf("%d",&p[i]);
for(int i = 1;i<=n;i++){
int x;
scanf("%d",&x);
a[p[i]] = x;
}
f[0][0][n+1] = 1;
for(int i = 1;i<=n;i++){
for(int j = 0;j<=q;j++){
for(int k = 1;k<=n+1;k++){
f[i][j][min(k,a[i])]+=f[i-1][j][k];
f[i][j][min(k,a[i])]%=mod;
if(a[i]<k){
f[i][j+1][k]+=f[i-1][j][k];
f[i][j+1][k]%=mod;
}
}
}
}
for(int i = 1;i<=n+1;i++)
ans = (f[n][q][i]+ans)%mod;
printf("%lld",ans);
return 0;
}
梦与现实间挣扎着,所求为何
你可以借走我的文章,但你借不走我的智慧 虽然我是傻逼本文来自博客园,作者:cztq,转载请注明原文链接:https://www.cnblogs.com/cztq/p/17558671.html