2022年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)
2.Setsuna的K数列(进制)
3.G 天气预报 (二分+前缀和)
4.史东薇尔城(最短路径dijstra)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n;
cin>>n;
ll m=n,ans=1,k=n;
while(m){
if(m%2==1){
ans=ans*n;
ans%=(k+2);
}
n=n*n;
n%=(k+2);
m/=2;
}
cout<<ans%(k+2);
return 0;
}
例如:计算3的10次方时,
3^10=(3^2)^5 = 9^5 =9*9^4 =9*(81)^2……
遇到奇数幂时,先给ans乘上原来的数,再将原数平方,即做到log2n的时间复杂度
2.Setsuna的K数列(进制)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long mod=1e9+7;
ll ppow(ll k,ll i){//快速幂求次方
ll ans=1;
while(i){
if(i%2==1){
ans=ans*k;
ans%=mod;
}
k=k*k%mod;
i/=2;
}
return ans%mod;
}
int main(){
ll sum=0;
ll n,k;
cin>>n>>k;
ll i=0;
while(n){//将n转化为二进制数按k进制还原
int a=n%2; //cout<<a<<endl;
ll b=ppow(k,i);
sum+=a*b;
// cout<<sum<<endl;
sum%=mod;
n/=2;
i++;
}
cout<<sum;
return 0;
}
思路:
不难发现,
K
数列本质就是每一个
K
进制位只能取
0
或
1
,这很像二进制,即第
n
个数就是
把
n
表示成二进制然后按
K
进制还原即可。
3.剪绳子
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int c[N],sum[N];
int mp[1000100];
int main(){
mp[0]=0;
mp[1]=1000000;
int q;
cin>>q;
int k=2;
while(q--){
char e;
cin>>e;
if(e=='C'){
double f;
cin>>f;
mp[k++]=f*100000+0.5;
}
else{
double ll;
cin>>ll;
int l=ll*100000+0.5;
sort(mp,mp+k);
for(int i=0;i<k;i++){
if(l>=mp[i]&&l<=mp[i+1]){
cout<<fixed<<setprecision(5)<<(mp[i+1]-mp[i])*1.0/100000<<endl;
break;
}
}
}
}
return 0;
}
3.天气预报(二分加前缀和)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+9;
ll aa[N],bb[N];
int n,a,b;
int check(ll i,ll j){//检查该区间的晴朗天数和坏天气天数是否满足要求
ll p=aa[j]-aa[i-1];
ll q=bb[j]-bb[i-1];
if(p>=a&&q>=b)return 1;
else return 0;
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n>>a>>b;
string s;
cin>>s;
ll ans=0;
//cout<<s.size()<<endl;
for(int i=1;i<=n;i++){//前缀和:当两个前缀和相减时就可以求出该段区间内有多少天晴朗,即判断是否满足情况
aa[i]=aa[i-1];//对天气晴朗的情况求前缀和
bb[i]=bb[i-1];//对下毒蛙的情况求前缀和
if(s[i-1]=='0')aa[i]++;
else bb[i]++;
}
/*
以样例1为例
5天内
天晴:10101
天坏:01011
天晴前缀和:11223
例:第三天到第一天有aa[3]-aa[1-1]=2-0=2天晴朗
天坏前缀和:01122
*/
if(a==0&&b==0)ans++;//特殊情况:当a和b均为0时,可以一天也不选
for(int i=1;i<=n;i++){
ll l=i,r=n;//左右两个指针
while(l<r){//左右指针相遇跳出循环
ll mid=(l+r)/2;//二分
if(check(i,mid))r=mid;//若左端点到中间区间满足条件,右指针往左移,缩小满足条件数
else l=mid+1;//否则左指针往右移,将满足天数的范围扩大
}
if(check(i,l))ans+=(n-l+1);//二分边界不一定满足,再次判断,若满足,则从l到n的i均满足,(往后只会比a,b天数更多,所以一定满足,都加到ans中)
}
cout<<ans<<endl;
return 0;
}
4.史东薇尔城(最短路径)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>p;
const ll N=1e6+10;
vector<p>h[N];
ll dist[N],st[N];
void dijstra(){
memset(dist,0x3f,sizeof(dist));//初始化每个点到根节点的距离为无穷大
priority_queue<p,vector<p>,greater<p> >q;
q.push({0,1});//放入根节点
dist[1]=0;//根节点距自己的距离为0
while(!q.empty()){//队列为空时跳出循环
p now=q.top();q.pop();//取队头元素
int ne=now.second;//下一个距离自己最近的点名
// int dis=now.first;//
if(st[ne])continue;
st[ne]=1;
for(auto it:h[ne]){//遍历该点周围连接的点
if(dist[it.first]>dist[ne]+it.second){//松弛操作
dist[it.first]=dist[ne]+it.second;//如果该点到根节点的距离大于,自己的前驱节点到根节点的距离加上到自己的距离,就更新
q.push({dist[it.first],it.first});//把目前最新更新的点加入队列
}
}
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int v,w,d;
cin>>v>>w>>d;
h[v].push_back({w,d});//建立图(连边加权值)
h[w].push_back({v,d});//无向图,两点能相互到达
}
dijstra();//最短路径搜素
int t;
cin>>t;
while(t--){
int x,y;
cin>>x>>y;
cout<<dist[x]+dist[y]<<endl;
}
return 0;
}
关于dijstta算法:Dijkstra算法详解(完美图解、趣学算法)_wjyGrit的博客-CSDN博客_dijkstra算法