Ural Championship 2012

  IDOrigin Title
 Problem AURAL 1900Brainwashing Device
 Problem BURAL 1901Space Elevators
 Problem CURAL 1902Neo-Venice
 Problem DURAL 1903Unidentified Ships
 Problem EURAL 1904The Lessons of the Past
 Problem FURAL 1905Travel in Time
 Problem GURAL 1906The Lost Civilization
 Problem HURAL 1907Coffee and Buns
 Problem IURAL 1908Brute-force Search
 Problem JURAL 1909Space Recon

         题目异常难懂。。还有就是代码能力太差了,往往出题速度和想题速度不成正比。。。导致出题异常的慢。。。得注意提高代码能力了,唉
         A题比较容易懂,是一道输出路径的dp。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 550;

int out[maxn], pt[maxn][maxn];
int a[maxn][maxn], dp[maxn][maxn], add[maxn][maxn];

int main()
{
    int n, k;
    while(scanf("%d%d", &n, &k) != EOF)
    {
        CLR(a, 0);
        for(int i = 1; i < n; i ++)
        {
            for(int j = i + 1; j <= n; j ++)
            {
                scanf("%d", &a[i][j]);
            }
        }
        for(int i = 1; i <= n; i ++)
        {
            out[i]= 0;
            for(int j = 1; j <= n; j ++)
            {
                out[i] += a[i][j];
            }
        }
        CLR(add, 0);
        for(int i = 0; i <= n; i ++)
        {
            int tot = 0, sub = 0;
            for(int j = i + 1; j <= n; j ++)
            {
                tot += out[j];
                for(int s = i + 1; s <= j; s ++)
                    sub += a[s][j];
                add[i][j] = tot - sub;
            }
        }
        CLR(dp, 0);
        for(int j = 1; j <= k; j ++)
        {
            for(int i = 1; i < n; i ++)
            {
                for(int l = 0; l < i; l ++)
                {
                    int tmp1 = dp[j - 1][l] + add[l][i] , &tmp2 = dp[j][i];
                    if(tmp1 >= tmp2)
                    {
                        tmp2 = tmp1;
                        pt[j][i] = l;
                    }
                }
            }
        }
        int ans = 0, id;
        for(int i = 1; i <= n; i ++)
            if(dp[k][i] >= ans) ans = dp[k][i], id = i;
        printf("%d\n", ans);
        vector<int> path;
        for(int i = k; i; i --)
        {
            path.push_back(id);
            id = pt[i][id];
        }
        sort(path.begin(), path.end());
        for(int i = 0; i < k; i ++)
        {
            printf("%d%c", path[i], i == k - 1 ? '\n' : ' ');
        }
    }
}

             B题要求的是电梯最多坐两个人,每次重要值之和不超过s,求最多的次数。直接贪心就可以了。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define LL long long
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int maxn = 100100;
const int INF = 123456789;

vector<int> los, ans;
int v[maxn];

int main()
{
    int n, s;
    while(scanf("%d%d", &n, &s) != EOF)
    {
        int tot = 0;
        for(int i = 0; i < n; i ++)
        {
            scanf("%d", &v[i]);
        }
        sort(v, v + n);
        int l = 0, r = n - 1;
        ans.clear();los.clear();
        while(l < r)
        {
            if(v[l] + v[r] <= s)
            {
                los.push_back(v[l]);
                l ++;
            }
            else
            {
                ans.push_back(v[l ++]);
                ans.push_back(v[r --]);
            }
        }
        if(l == r) los.push_back(v[l]);
        sort(los.begin(), los.end());
        for(int i = los.size() - 1; i >= 0; i --)
            ans.push_back(los[i]);
        for(int i = 0; i < n; i ++)
        {
            if(ans[i] + ans[i + 1] <= s) i ++;
            tot ++;
        }
        printf("%d\n", tot);
        for(int i = 0; i < n; i ++)
        {
            printf("%d%c", ans[i], i == n - 1 ? '\n' : ' ');
        }
    }
}

             C题是一道很水的题目。。
             D题我没看。。队友做的。组合数学,不过需要注意的是开5000*5000的数组会MLE。而且仔细想想是不需要开那么大的数组的,组合数只要求3列就行了。。粘上队友的代码。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <stack>
#include<map>
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 5100
#define E exp(double(1))
#define eps 1e-7
using namespace std;

#ifdef __int64
    typedef __int64 LL;
#else
    typedef long long LL;
#endif

LL mod = 1000000007;

LL str[maxn];
LL s[maxn];

LL ext_gcd(LL a,LL b,LL &x,LL &y){
    LL t,ret;
    if(!b){
        x=1,y=0;
        return a;
    }
    ret=ext_gcd(b,a%b,x,y);
    t=x,x=y,y=t-a/b*y;
    return ret;
}
//逆元(b/a)%mod
LL inv(LL a,LL b,LL mod){
    LL x,y;
    ext_gcd(a,mod,x,y);
    return (x*b%mod+mod)%mod;
}

void init(){
    str[0]=1;
    for(int i=1;i<=5001;i++){
        str[i]=str[i-1]*i%mod;
        s[i]=inv(str[i],1,mod);
    }
}

LL fun(LL m,LL n) {
    if(n>m)return 0;
    if(n==0||m==0||n==m)return 1;
    return (str[m]*s[n]%mod)*s[m-n]%mod;
}
LL c[maxn];

int main(){
    LL k,n,t,x;
    init();
    while(scanf("%lld%lld",&n,&t)!=EOF){
        for(int i=1;i<=n;i++){
            scanf("%lld",&c[i]);
        }
        scanf("%lld%lld",&k,&x);
        LL val = c[k];
        LL s1=0,s2=0,ss=0;

        for(int i=1;i<=n;i++){
            if(c[i]>val)s2++;
            if(c[i]<val)s1++;
            if(c[i]==val)ss++;
        }

        LL ans = 0;
        LL l = x-1;
        LL r = t-x;

        for(int i=max(0LL,x-1-s1);i<ss&&i<=l;i++){
            for(int j=max(t-x-s2,0LL);j<ss-i&&j<=r;j++){
                LL q = fun(ss-1,i+j) *fun(s1,x-1-i)%mod*fun(s2,t-x-j)%mod;
                ans+=q;
                ans%=mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

            E题到最后都没看懂题目。。。队友猜了一个题意,很晚才ac的。。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <stack>
#include<map>
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 400000
#define E exp(double(1))
#define eps 1e-7
using namespace std;

#ifdef __int64
    typedef __int64 LL;
#else
    typedef long long LL;
#endif

int ans[maxn];
int h[maxn];
struct as{
    int s,t;
    as(){}
    as(int s,int t):s(s),t(t){}
};
vector<as>v;

int main(){
    int i,j,k;
    int n,cnt;
    while(scanf("%d",&n)!=EOF){
        memset(ans,0,sizeof ans);
        for(int i=0;i<n;i++){
            scanf("%d",&h[i]);
        }
        for(int i=-12000;i<12000;i++){
            int pos = i+12000;
            int now = i;
            for(int j=0;j<n;j++){
                now = abs(now - h[j]);
            }
            if(now ==0 ||now==1)ans[pos]=true;
        }
        int cnt = 0;
        v.clear();
        int l,r;
        for(int i=-12000;i<12000;){
            int pos = i+12000;
            if(ans[pos]){
                l = pos;
                r=l;
                while(ans[r]==true)r++;
                v.push_back(as(l,r-1));
                i=r-12000;
            }else{
                i++;
            }
        }
        printf("%d\n",v.size());
        for(int i=0;i<v.size();i++){
            printf("%d %d\n",v[i].s-12000,v[i].t-12000);
        }
    }
    return 0;
}

              F题要求在同一个位置不能同一个时间待两次,只要我们按最短路求,那就肯定不会出现这种情况。因为假如第一次就可以走那条路,那第二次同一时间到达这里就完全没必要了。另为注意一些优化,不然程序会退化到O(m^2)。(优化见代码部分)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <queue>
#include <cstdio>
#include <cmath>
#include <stack>
#include<map>
#define PI acos(-1.0)
#define inf 0x3f3f3f3f
#define maxn 100100
#define eps 1e-7
using namespace std;

#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif

struct Edge
{
    int u, v, b, e, id, fa;
    bool operator < (const Edge &rhs) const
    {
        return b < rhs.b;
    }
    void pt()
    {
        printf("%d %d %d %d %d\n", u, v, b, e, id);
    }
}E[maxn];

int fir[maxn], nxt[maxn], tot;

void AddEdge(int u, int v)
{
    nxt[tot] = fir[u]; fir[u] = tot ++;
}

int n, m, sid, eid, stm, etm;

bool vis[maxn];

int bfs()
{
    queue<int> Q;memset(vis, false, sizeof(vis));
    for(int i = fir[sid]; ~i; i = nxt[i]) if(E[i].b >= stm)
    {
        Q.push(i);vis[i] = true;
    }

    while(!Q.empty())
    {
        int now = Q.front();Q.pop();
        Edge e = E[now];
        if(e.v == eid && e.e <= etm) return now;
        for(int i = fir[e.v]; ~i; i = nxt[i])
        {
            if(E[i].b < e.e)
            {
                fir[e.v] = i;///每次修改邻接表的初始指针位置,因为走过的路就完全没必要再走一遍了。
                break; /// 因为是有序的,所以可以直接跳出。
            }
            if(vis[i]) continue;
            E[i].fa = now;
            if(E[i].v == eid && E[i].e <= etm) return i;
            vis[i] = true;
            Q.push(i);
        }
    }
    return -1;
}

int main()
{
//    freopen("in.txt", "r", stdin);
    while(scanf("%d%d", &n, &m) != EOF)
    {
        tot = 1;memset(fir, -1, sizeof fir);
        for(int i = 1; i <= m; i ++)
        {
            int u, v, b, e;
            scanf("%d%d%d%d", &u, &v, &b, &e);
            E[i].u = u; E[i].v = v;E[i].b = b;
            E[i].e = e;E[i].fa = 0;E[i].id = i;
        }
        sort(E + 1, E + m + 1);
        for(int i = 1; i <= m; i ++)
        {
            AddEdge(E[i].u, E[i].v);
        }
        scanf("%d%d%d%d", &sid, &eid, &stm, &etm);
        if(sid == eid && stm <= etm)
        {
            puts("0");
            continue;
        }
        int ans = bfs();
        if(ans == -1)
        {
            puts("Impossible");
        }
        else
        {
            vector<int> pt;
            while(ans)
            {
                pt.push_back(E[ans].id);
                ans = E[ans].fa;
            }
            printf("%d\n", pt.size());
            for(int i = pt.size() - 1; i >= 0; i --)
            {
                printf("%d%c", pt[i], i == 0 ? '\n' : ' ');
            }
        }
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值