厦门大学“网宿杯“17届程序设计竞赛决赛

↘锁芯ラ 提交于 2020-07-27 22:01:11

E:芜湖起飞

https://ac.nowcoder.com/acm/contest/5945/E

 

每条边的权值为 kx+b,可知这是一个一次函数。

但是每条边的单调性并不是相同的,所以综合应该为一个二次函数。

求二次函数的方法一般为 三分法,所以这题只需要 三分答案+dij便可。

#include <bits/stdc++.h>
 
#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
#define fcdate freopen("in.txt", "w", stdout)
 
using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<ll, ll> pii;
 
#define M 120000
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define mod 998244353
#define W(a) while (a)
#define ms(a, b) memset(a, b, sizeof(a))
#define debug(a) cout << #a << " == " << a << endl
#define false_stdio ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
 
ll n, m, H,st=1;
struct Data {
    ll v;
    ll k,b;
};
ll dis[M];
vector<Data>edge[M];

ll dij(ll x) {
    ms(dis, 0x7f), dis[st] = 0;
    priority_queue<pii, vector<pii>, greater<pii>>num;
    num.push(pii(0, st));
    W(!num.empty()) {
        pii head = num.top(); num.pop();
        int u = head.second;
        if (dis[u] < head.first)continue;
        int len = edge[u].size();
        for (int i = 0; i < len; i++) {
            ll v = edge[u][i].v;
            ll w = edge[u][i].k*x+edge[u][i].b;
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                num.push(pii(dis[v], v));
            }
        }
    }
    return dis[n];
}

int main() {
    false_stdio;
    cin >> n >> m >> H;
    for (int i = 1, u, v, k,b; i <= m; i++) {
        cin >> u >> v >> k>>b;
        if(u==v)continue;
        edge[u].push_back(Data{ v,k,b });
    }

    int l=0,r=H;
    W(r-l>10){
        int lm=l+r>>1;
        int rm=(lm+r)>>1;
        if(dij(lm)>dij(rm))r=rm;
        else l=lm;
    }
    ll mx=0;
    for(int i=l;i<=r;i++){
        mx=max(mx,dij(i));
    }
    cout<<mx<<endl;
    

    return 0;
}

 

这题多捞啊

https://ac.nowcoder.com/acm/contest/5945/F

 

简单的找规律。

当n为偶数时,答案为:n-1个 1 和 n+1

当n为奇数数,答案为:(n-1个 1 和 n+1)   和  ( n个 2)

注意下格式和 n==1的情况即可

 

#include <bits/stdc++.h>

#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
#define fcdate freopen("in.txt", "w", stdout)

using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<int,int> pii;

#define M 2050
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define mod 1000007
#define eps 0.000001
#define W(a) while (a)
#define ms(a, b) memset(a, b, sizeof(a))
#define debug(a) cout << #a << " == " << a << endl
#define false_stdio ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)

int n;

int main(){
    false_stdio;
    cin>>n;
    if(n==1){
        cout<<2<<endl;
    }
    else{
        if(n&1){
            for(int i=1;i<n;i++)cout<<1<<" ";
            cout<<n+1<<endl;
            for(int i=1;i<n;i++)cout<<2<<" ";
            cout<<2<<endl;
        }
        else{
            for(int i=1;i<n;i++)cout<<1<<" ";
            cout<<n+1<<endl;
        }
    }
    
   
    return 0;
}

 

正方形打野

https://ac.nowcoder.com/acm/contest/5945/G

很明显的贪心模拟题。

我们遍历一遍。

判断当前格子是否已经被定义了,如果还没定义,最小可以放多少,那么最大可以放多远,最远端最小可以放的 和 当前格子的最小是一样的吗。

#include <bits/stdc++.h>

#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
#define fcdate freopen("in.txt", "w", stdout)

using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<int,int> pii;

#define M 2050
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define mod 100000007
#define eps 0.000001
#define W(a) while (a)
#define ms(a, b) memset(a, b, sizeof(a))
#define debug(a) cout << #a << " == " << a << endl
#define false_stdio ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)


int n, m;
int nxt[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
char mp[M][M];
 
char get(int x, int y) {
    if(mp[x][y])return mp[x][y];
    char res = 'A';
    W(true){
        int flag=0;
        for(int k=0;k<4;k++){
            if(res==mp[x+nxt[k][0]][y+nxt[k][1]]){
                flag=1;
                break;
            }
        }
        if(!flag)break;
        else res++;
    }
    //debug(res);
    return res;
}

 
int main() {
    false_stdio;
    cin >> n >> m;
    for (int x = 1;x <= n;x++) {
        for (int y = 1; y <= m;y++){
            if (mp[x][y])continue;
            char ch = get(x, y);
            int len = 1;
            W(x + len <= n && y + len <= m && get(x, y + len) == ch)len ++;
            //debug(len);
            for (int i = 0; i < len;i++){        
                for (int j = 0; j < len;j++){        
                    mp[x + i][y + j] = ch;
                }
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cout<<mp[i][j];
        }
        cout<<endl;
    }
    return 0;
}
    

 

 

时间管理

https://ac.nowcoder.com/acm/contest/5945/H

很简单的线段树操作。

区间更新,懒标记,区间求和。

难点在于,把区间内的每一个数替换为与给出的x的gcd。

当然不能一直一个个暴力修改,我们可以考虑到,当一个区间内的值全相同的时候,那么这个区间的gcd当然也相同。

做一个区间标记即可。

 

#include <bits/stdc++.h>
 
#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
#define fcdate freopen("in.txt", "w", stdout)
 
using namespace std;
typedef double dou;
typedef long long ll;
typedef pair<ll, ll> pii;
 
#define M 200050
#define pi acos(-1.0)
#define inf 0x3f3f3f3f
#define mod 998244353
#define W(a) while (a)
#define ms(a, b) memset(a, b, sizeof(a))
#define debug(a) cout << #a << " == " << a << endl
#define false_stdio ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
 

int n,m;
ll a[M];
struct Data{
    ll gd;
    ll sum;
    bool tag;
}tree[M<<2];

ll gcd(ll x, ll y){
    return y ? gcd(y, x % y) : x;
}

void built(int l,int r,int k){
    if(l==r){
        cin>>tree[k].sum;
        tree[k].gd=tree[k].sum;
        tree[k].tag=true;
        return;
    }
    int mid=l+r>>1;
    built(l,mid,k<<1);
    built(mid+1,r,k<<1|1);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    if(tree[k<<1].tag && tree[k<<1|1].tag && tree[k<<1].gd==tree[k<<1|1].gd){
        tree[k].tag=true;
        tree[k].gd=tree[k<<1].gd;
    }
    else{
        tree[k].tag=false;
    }
}

void push_up(int l,int r,int k){
    tree[k<<1].tag=tree[k<<1|1].tag=tree[k].tag;
    tree[k<<1].gd=tree[k<<1|1].gd=tree[k].gd;
    int mid=l+r>>1;
    tree[k<<1].sum=tree[k<<1].gd*(mid-l+1);
    tree[k<<1|1].sum=tree[k<<1|1].gd*(r-mid);
}

void updata(int l,int r,int k,int x,int y,ll z){
    if(x<=l && r<=y){
        if(tree[k].tag){
            tree[k].gd=gcd(tree[k].gd,z);
            tree[k].sum=tree[k].gd*(r-l+1);
            //cout<<"# "<<l<<" "<<r<<" "<<tree[k].gd<<endl;
            return;
        }
    }
    if(tree[k].tag)push_up(l,r,k);
    int mid=l+r>>1;
    if(x<=mid)updata(l,mid,k<<1,x,y,z);
    if(y>mid)updata(mid+1,r,k<<1|1,x,y,z);

    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    if(tree[k<<1].tag && tree[k<<1|1].tag && tree[k<<1].gd==tree[k<<1|1].gd){
        tree[k].tag=true;
        tree[k].gd=tree[k<<1].gd;
    }
    else{
        tree[k].tag=false;
    }
}


ll query(int l,int r,int k,int x,int y){
    if(x<=l && r<=y){
        if(tree[k].tag){
            return tree[k].sum;
        }
    }
    if(tree[k].tag)push_up(l,r,k);
    int mid=l+r>>1;
    ll sum=0;
    if(x<=mid)sum+=query(l,mid,k<<1,x,y);
    if(y>mid)sum+=query(mid+1,r,k<<1|1,x,y);
    return sum;
}

int main(){
    false_stdio;
    cin>>n>>m;
    built(1,n,1);
    W(m--){
        int opt,l,r,x;
        cin>>opt;
        if(opt==1){
            cin>>l>>r>>x;
            updata(1,n,1,l,r,x);
        }
        else{
            cin>>l>>r;
            cout<<query(1,n,1,l,r)<<endl;
        }
    }
    
    return 0;
}

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!