题目链接

A-红石音乐

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_#include

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_#define_02

我打比赛怎么还学会了音乐知识

题意:大概就是有音符A1 B1  C1 D1 到 A7 B7 其中A1#代表升半调,A1b 代表降半调。B 到C E到F  只有半调

给你一个调,要求从5个基本调每次往上调半调 调到当前的调 的最小次数是多少

做法:预处理所有调所在第几层就可以了。需要注意 的是数据范围含有b 这种降半调的 就很坑。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
 
inline ll read()
{
    ll x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
map<string,int>mp;
int main()
{
    int id=0;
    for(int i=1;i<=8;++i){
        char num=i+'0';
        for(int j=0;j<7;++j){
            char ch=j+65;
            string s;
            s+=ch;
            s+=num;
            s+="b";
            mp[s]=id;
            s="";
            s+=ch;
            s+=num;
            mp[s]=++id;
            //cout<<s<<endl;
            if(j==1||j==4) continue;
            s="";
            s+=ch;
            s+=num;
            s+="#";
            mp[s]=++id;
            //cout<<s<<endl;
        }
 
 
        //s+="F";s+=c;s+="#";
    }
 
    int n=read();
    int res=0;
    rep(i,1,n)
    {
        string s;
        cin>>s;
        int ans=100000;
        if(mp[s]>=mp["F1#"]) ans=min(ans,mp[s]-mp["F1#"]);
        if(mp[s]>=mp["F2#"]) ans=min(ans,mp[s]-mp["F2#"]);
        if(mp[s]>=mp["F3#"]) ans=min(ans,mp[s]-mp["F3#"]);
        if(mp[s]>=mp["F4#"]) ans=min(ans,mp[s]-mp["F4#"]);
        if(mp[s]>=mp["F5#"]) ans=min(ans,mp[s]-mp["F5#"]);
        res+=ans;
    }
    printf("%d\n",res);
}

D-斐波那契数列?

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_i++_03

做法:这题一眼,嗯 矩阵快速幂没跑了,找模数的时候发现没有,居然是求浮点型的,这题有一招巧招:暴力加,加到后面这个除法就特别小了,就没必要继续求了。

#include<bits/stdc++.h>
using namespace std;
double a[505];
int main()
{
    int n;cin>>n;
    a[1]=0.5;
    a[2]=0.25;
    double ans=0;
    for(int i=1;i<=n;i++)
    {
        if(i>2)a[i]=a[i-1]*0.5+a[i-2]*0.25;
        if(a[i]<1e-11)break;
        ans+=a[i];
    }
    printf("%.9lf",ans);
    return 0;
}

E-樱桃蛋糕

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_#define_04

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_#define_05

做法:由于x 、y大于0,所以向上和向右走无需考虑,向下和向左的保存。

刚开始的时候,考虑向下走:最短走到y=0的位置,所以当前这个点的最长时间是y,

如果y>=x 则代表可以相遇,那么相遇一定是中间的位置,原路返回到家,总时间消耗就是x+y

模拟一下就可以了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,mod=1e9+7;
int n,m;
struct node{
    int x,y,d;
    bool operator<(const node &z)const{
        return x+y<z.x+z.y;
    }
}a[N];
int main()
{
    cin>>n;
    for(int i=1,x,y,d;i<=n;i++){
        scanf("%d%d%d",&x,&y,&d);
        if(d==1||d==3)continue;
        if(d==2)a[++m]={x,y,d};
        else a[++m]={x,y,d};
    }
    sort(a+1,a+1+m);
    int now=0,ans=0;
    for(int i=1;i<=m;i++){

        if(a[i].d==2){
            if(a[i].y-now>=a[i].x){
                ans++;now=a[i].x+a[i].y;
            }
        }
        else{
            if(a[i].x-now>=a[i].y){
                ans++;
                now=a[i].x+a[i].y;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

F-爱买手办的张三

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_c++_06

简单题

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
 
inline ll read()
{
    ll x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
const int N=32;
int f[N],X[N],len;
vector<int>ans;
int mx;
void dfs(int id,int val)
{
    if(ans.size()>mx) return ;
    if(id>len){
        ans.push_back(val);
        return ;
    }
    dfs(id+1,val+X[id]);
    dfs(id+1,val);
}
int main()
{
    f[0]=1;
    rep(i,1,30) f[i]=f[i-1]*2;
    mx=1000000;
    int x=read();
    for(int i=0;i<=30;++i){
        if(x&(1<<i)) X[++len]=f[i];
    }
    dfs(1,0);
    printf("1\n%d\n",x);
    sort(ans.begin(),ans.end());
    printf("%d\n",ans.size());
    for(int v:ans) printf("%d\n",v);
 
}

J-红绿灯

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_c++_07

做法:补题,看官方题解

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_#include_08

大佬的题解:

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_#pragma_09

大概就是构造合法的 绿黄红 的颜色顺序,且不能有交叉或者顺序不对 两种情况。

#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  N = 1e6 + 5;

map<pair<int,string>, bool> v;
int cnt[N];
ll n,T;

int check(){
    string t;
    for(int i=0;i<T;i++){
        if(t=="Yellow" && v.count(mp(i,"Green"))) return 1;//黄绿
        if(t=="Red" && v.count(mp(i,"Yellow"))) return 1;//红黄
        //if(t=="Green" && v.count(mp(i,"Red"))) return 1;//绿红 ??56行的代码保证了没有这种情况
        if(t=="Red" && v.count(mp(i,"Green"))) return 1;//红绿
        if(cnt[i]>1) return 1;
        if(v.count(mp(i,"Green"))) t="Green";
        if(v.count(mp(i,"Yellow"))) t="Yellow";
        if(v.count(mp(i,"Red"))) t="Red";
    }
    return 0;
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin>>n>>T;
    int m1=0,m2=INF;
    int flag=0;
    for(int i=1;i<=n;i++){
        int x;string s;
        cin>>x>>s;
        if(flag) continue;
        x=x%T;
        if(s=="Yellow" && x<=0) {cout<<i<<'\n';flag=1;}//黄前面没有绿了
        if(flag) continue;
        if(s=="Red" && x<=1) {cout<<i<<'\n';flag=1;}//红前面不够绿黄放下
        if(flag) continue;
        if(s=="Green" && x>=T-2) {cout<<i<<'\n';flag=1;}//绿后面没有黄红的位置
        if(flag) continue;

        if(s=="Yellow" && x>=T-1) {cout<<i<<'\n';flag=1;}//黄后面没有红的位置
        if(flag) continue;
        if(s=="Green") m1=max(m1,x);//分界线m1,m2
        if(s=="Red") m2=min(m2,x);

        if(m1+1>=m2) {cout<<i<<'\n';flag=1;}
        if(flag) continue;

        if(!v.count(mp(x,s))) v[mp(x,s)]=true,cnt[x]++;

        if(check()) {cout<<"check"<<i<<'\n';flag=1;}
    }
    if(flag) return 0;
    cout<<"Correct!\n";
    return 0;
}
/*
3 4
0 Green
1 Green
2 Red

*/

 

M-送礼物

2020年第十四届山东大学程序设计竞赛(重现赛)(A 模拟,D暴力,E(思维) F签到 ,J 模拟 M(线段树))_#pragma_10

做法:线段树维护最长上升子序列,经典题了。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
    ll x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
 
const int N=2e5+10;
ll a[N],ans,X[N],len;;
int n,fa[N];
 
 
 
/*线段树部分*/
struct tree
{
    int num,id;
}mx[4*N];
 
tree Max(tree a,tree b)
{
    if(a.num>b.num) return a;
    else if(a.num<b.num) return b;
    else if(a.id>b.id) return a;
    return b;
}
 
tree qu(int id,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr) return mx[id];
    tree ans={0,0};
    int mid=l+r>>1;
    if(ql<=mid) ans=qu(id<<1,l,mid,ql,qr);
    if(qr>mid) ans=Max(ans,qu(id<<1|1,mid+1,r,ql,qr));
    return ans;
}
int get(ll x)
{
    return lower_bound(X+1,X+1+len,x)-X;
}
void up(int id,int l,int r,int pos,int num,int tid)
{
    if(l==r){
        if(num>=mx[id].num){mx[id].num=num;mx[id].id=tid;}
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid) up(id<<1,l,mid,pos,num,tid);
    else up(id<<1|1,mid+1,r,pos,num,tid);
    mx[id]=Max(mx[id<<1],mx[id<<1|1]);
}
 
 
 
 
 
int main()
{
    n=read(),ans=read();
    rep(i,1,n){a[i]=read();X[++len]=a[i];fa[i]=i;}
 
    sort(X+1,X+1+len);
    len=unique(X+1,X+1+len)-X-1;
 
 
    int now=0,mxx=0;
    rep(i,1,n)
    {
        int pos=get(a[i]);
        tree t={0,0};
        if(pos-1>=1) {
            t=qu(1,1,len,1,pos-1);
            if(t.id!=0) fa[i]=t.id;
            //printf("i:%d tid:%d\n",i,t.id);
        }
 
        if(t.num+1>=mxx){mxx=t.num+1;now=i;}
 
        up(1,1,len,pos,t.num+1,i);
    }
 
 
    stack<int>sta;
    while(now!=fa[now]){
        ans+=a[now];sta.push(now);now=fa[now];
    }
    ans+=a[now];
    sta.push(now);
    printf("%lld\n%d\n",ans,sta.size());
    while(sta.size()) printf("%d\n",sta.top()),sta.pop();
}
/*
10 0
-1 -2 -3 -4 5 6 7 8 -10 9
*/