第一场

MARK一下~~
http://acm.csu.edu.cn/OnlineJudge/contestrank.php?cid=2098
A:
题意:给出几个树,让你用最少的边将他们联通,且树的直径最小~
思路:
求出每个树的直径,把其看成一个链,那么肯定是将链的中点连到一起才能使最后直径最短,然后因为直径有可能相等,最多用2条边连出一条直径,所以讨论一下用0,1,2条边连的情况,取最大值就ok了!
这里求树的直径采用了双BFS法,因为是bfs,所以两次都一定找到的是端点~

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <queue>
#define mem0(a) memset(a,0,sizeof(a))
using namespace std;
template<class T> T MAX(T a, T b) { return a > b ? a : b; }
template<class T> T MIN(T a, T b) { return a < b ? a : b; }
const int maxn = 200010;

int hh[maxn];

struct nod {
    int to,next,w;
} edge[maxn];

int head[maxn],ip;

int n,m;

bool vis1[maxn], vis2[maxn];
vector<int>dd;
int  dis1[maxn], dis2[maxn];
int f(int x){
    return (x+1)/2;
}
void init() {
    ip=0;
    memset(head,-1,sizeof(head));
}

void add(int u,int v,int w) {
    edge[ip].to=v;
    edge[ip].w=w;
    edge[ip].next=head[u];
    head[u]=ip++;
}

void BFS1(int u, int &ans, int &lv) {
    queue<int > Q;
    Q.push(u);
    vis1[u]=1;
    while(!Q.empty()) {
        int top = Q.front();
        Q.pop();
        for(int i=head[top]; i!=-1; i=edge[i].next) {
            int v = edge[i].to;
            hh[v]=1;
            if(!vis1[v]) {
                vis1[v]=1;
                Q.push(v);
                dis1[v]=dis1[top]+edge[i].w;
                if(ans < dis1[v]){
                    ans = dis1[v];
                    lv = v;
                }
            }
        }
    }
}
void BFS2(int u, int &ans, int &lv) {
    queue<int > Q;
    Q.push(u);
    vis2[u]=1;
    while(!Q.empty()) {
        int top = Q.front();
        Q.pop();
        for(int i=head[top]; i!=-1; i=edge[i].next) {
            int v = edge[i].to;
            hh[v]=1;
            if(!vis2[v]) {
                vis2[v]=1;
                Q.push(v);
                dis2[v]=dis2[top]+edge[i].w;
                if(ans < dis2[v]){
                    ans = dis2[v];
                    lv = v;
                }
            }
        }
    }
}

int TreeDiameter(int k) {
    int ans = 0;
    int u = 0; 
    BFS1(k, ans, u);
    ans = 0;
    BFS2(u, ans, u);
    return ans;
}

int main() {
    while(~scanf("%d%d",&n,&m)){
        mem0(hh);dd.clear();
        memset(vis1,0,sizeof(vis1));
        memset(dis1,0,sizeof(dis1));
        memset(vis2,0,sizeof(vis2));
        memset(dis2,0,sizeof(dis2));
        init();
        for(int i=0; i<=m-1; i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            add(u+1,v+1,1);
            add(v+1,u+1,1);
        }
        int D ;
        int maxxx=0;
        for(int i=1;i<=n;i++){
            if(hh[i]==0){
                D = TreeDiameter(i);
                maxxx=MAX(maxxx,D);
                dd.push_back(f(D));
            } 
        }
        sort(dd.begin(),dd.end());
        int size=dd.size();int ans=0;
        ans=max(ans,maxxx);
        if(dd.size()>=2)ans=max(ans,dd[size-1]+dd[size-2]+1);
        if(dd.size()>=3)ans=max(ans,dd[size-2]+dd[size-3]+2);
        printf("%d\n",ans);
    }      
    return 0;
}

B:
题意:求小于等于8的全排列,且相邻排列必须保证只有一步之差~
思路:构造题,首先递归求出n-1的,然后考虑插n,从右开始,每次都与左边一个交换位置~到最左边后则直接插在下一个n-1的最前面,这个可以用数学归纳法证明2个肯定一步之差~(子问题),然后往右的时候亦然~

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
int n;
vector<vector<int> > dfs(int n){
    if(n==1) {
        vector<vector<int> > a;
        vector<int>b;b.push_back(1);a.push_back(b);return a;
    }
    vector<vector<int> > o=dfs(n-1);
    vector<vector<int> > oo;
    int flag=1;int pos;
    for(int i=0;i<o.size();i++){
        int m=o[i].size();
        int cur=flag?n-1:0;
        if(flag)o[i].push_back(n);
        else o[i].insert(o[i].begin(),n);
        oo.push_back(o[i]);
        for(int j=0;j<m;j++){
            if(flag) pos=cur-1;
            else pos=cur+1;
            swap(o[i][pos],o[i][cur]);
            cur=pos;
            oo.push_back(o[i]);
        }
        flag^=1;
    }
    return oo;
}
int main(){
    scanf("%d",&n);
    vector<vector<int> >ans=dfs(n);
    for(int i=0;i<ans.size();i++){
        int m=ans[i].size();
        for(int j=0;j<m-1;j++){
            printf("%d ",ans[i][j]);
        }
        printf("%d\n",ans[i][m-1]);
    }


}

C:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
char tmp[4]={"PER"};
char s[310];

typedef pair<int,int> pii;

int main(){
    scanf("%s",s);int ans=0;
    for(int i=0;i<strlen(s);i++){
        if(s[i]!=tmp[i%3]) ans++;
    }
    printf("%d\n",ans);

    return 0;
}

D:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int manx=1e5+10;
int n,k;
queue<int >q;
int b;
typedef pair<int,int> pii;

int main(){
    scanf("%d%d",&n,&k);int ans=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&b);q.push(b);
        while(!q.empty()&&q.back()-q.front()>=1000){
            q.pop();
        }
        ans=max(ans,((int)q.size()+k-1)/k);
    }
    printf("%d\n",ans);
    return 0;
}

E:
贪心
每次都给后面的任务留出更早的结束时间~
这里注意erase(it)不是*it !!!

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int maxn=1e5+10;
struct D
{
    int x;
    bool operator < (const D& rbs)const{
        return x > rbs.x;
    }
    D(){}
    D(int _x){x = _x;
    }
};
int n,k;
struct node{
    int x,y;
}a[maxn];
multiset<D>s;
bool cmp(node a,node b){
    return a.y<b.y;
}
int main(){
   while(   scanf("%d%d",&n,&k)!=EOF){
    s.clear();
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].x,&a[i].y);  
    }
    sort(a+1,a+1+n,cmp);int ans=0;
    for(int i=1;i<=n;i++){
        multiset<D>::iterator it=s.lower_bound(D(a[i].x));
        //printf("%d\n",(*it).x);
        if(it!=s.end()){

            s.erase(it);
            ans++;s.insert(D(a[i].y));
        }
        else if(s.size()<k){
            s.insert(D(a[i].y));ans++;
        }

    }
    printf("%d\n",ans);
   }

}

F:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int manx=1e5+10;
int n,k;
set<int>s,ss;
queue<int >q;
typedef pair<int,int> pii;
const int maxn=1e4+10;
int f,t[maxn];
int st,e,a,b;
int main(){
    scanf("%d",&f);int flag=1;
    for(int i=1;i<=f;i++){
        scanf("%d%d",&a,&b);s.clear();
        for(int i=0;i<=a;i++){
            s.insert(i);
        }
        for(int i=0;i<b;i++){
            scanf("%d%d",&st,&e);ss.clear();
            for(set<int>::iterator it=s.begin();it!=s.end();it++){
                if((*it-(e-st))>=0) ss.insert((*it-(e-st)));
                if((*it+(e-st))<=a) ss.insert((*it)+(e-st));
            }
            if(ss.empty()) {
                flag=0;continue;
            }
            swap(s,ss);
        }
    }
    if(!flag) printf("impossible\n");
    else puts("possible");


}

数据结构题,从半径入手,对每个x记录y的位置,然后判断边界二分就可了 ,详见代码~
G:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define gmax(a, b) ((a) > (b) : (a) : (b))
#define gmin(a, b) ((a) < (b) : (a) : (b))
#define mem0(a) memset(a,0,sizeof(a))
#define mem_1(a) memset(a,-1,sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
const int maxn=1e5+10;
multiset<int>mx[1010];
struct Node{
    int x,y;
}p[maxn];
struct node{
    int x,y,r;
}a[2010];
int n,m;
int main(){
    scanf("%d",&n);int xa,ya;int x,y,r;
    for(int i=1;i<=n;i++){
        scanf("%d%d",&xa,&ya);
        mx[xa].insert(ya);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&x,&y,&r);
        for(int xx=max(0,x-r);xx<=min(10000,x+r);xx++){
            int maxx=0;int minn=1000000007;
            for(int yy=max(0,y-r);yy<=min(10000,y+r);yy++){
                if((xx-x)*(xx-x)+(yy-y)*(yy-y)<=r*r){
                    maxx=max(maxx,yy);minn=min(minn,yy);
                }
            }
            multiset<int>::iterator it1=mx[xx].lower_bound(minn);
            multiset<int>::iterator it2=mx[xx].upper_bound(maxx);
            mx[xx].erase(it1,it2);
        }
    }
    int ans=0;
    for(int i=0;i<=10000;i++){
        ans+=mx[i].size();
    }
    printf("%d\n",ans);

}

H:
题意:
类似于节奏大师,每次会有音符掉落,击中则得一分,首先肯定了玩家技术超强,每个音符都肯定会打掉~然后增加了一个按钮,可以在充电时间充电,可以叠加,随时停止,但一旦释放就必须放完,释放期间内的音符价值为2分,重叠的释放和充电时间音符价值为1~(如果二者恰好接壤则无影响~,价值仍为2)
思路:
动态规划,best i 表示的是在i(充电的阶段)之前能得到的最大增加分数,然后枚举在每个区间开始充电到point,所能释放电到的最大j,(双指针法), 取最大的长度更新对应的best值就可以了~,答案最后需要加上n~
注意best和start下标相差1,表示的含义正好与上面相对~

resize的含义是:

如果n比当前的vector元素数目要小,vector的容量要缩减到resize的第一个参数大小,既n。并移除那些超出n的元素同时销毁他们。
如果n比当前vector元素数目要大,在vector的末尾扩展需要的元素数目,如果第二个参数val指定了,扩展的新元素初始化为val的副本,否则按类型默认初始化。
注意:如果n大于当前的vector的容量(是容量,并非vectorsize),将会引起自动内存分配。所以现有的pointer,references,iterators将会失效。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <cstdio>
using namespace std;

#define rep(i,a,b) for(__typeof(b) i=a; i<(b); ++i)

typedef vector<int> vi;
void improveMax(int &a, int b)
{
    a = max(a, b);
}
int main()
{
    int n, p;
    scanf("%d %d", &n, &p);

    unordered_map<int, int> ord;
    vi t(n);
    rep(i,0,n) {
        scanf("%d", &t[i]);
        ord[t[i]] = i;
    }

    vi next, starts(p), totpow;
    rep(i,0,p)
    {
        int s, e; scanf("%d %d", &s, &e);
        starts[i] = ord[s];
        next.resize(starts[i], i);
        totpow.resize(starts[i] + 1, (totpow.empty() ? 0 : totpow.back()));
        rep(j,ord[s],ord[e])
            totpow.push_back(totpow.back() + t[j + 1] - t[j]);
    }
    totpow.resize(n, totpow.back());
    next.resize(n, p);
    /*for(auto i: totpow){
        cout<<"totpow= "<<i<<endl;
    }
    for(auto i:next){
        cout<<"next= "<<i<<endl;
    }*/
    vi best(p + 1);
    rep(i,0,p)
    {
        int point = starts[i];
        rep(j,point+1,n)
        {
            while (point + 1 < n && totpow[point + 1] - totpow[starts[i]] <= t[j] - t[point + 1])
                point++;
           // cout<<"i=  "<<i<<"   j= "<<j<<"   "<<"point=  "<<point<<endl;
            improveMax(best[next[j]], best[i] + (j - point));
        }
    }
    cout << best[p] + n << endl;
}

J:
题意:
对于每个一行的文本串,最后一个字符串是前面的问句的答案
每次可以在一个句子的一半打断他进行抢答
问最有得分的期望值

建一个字典树,字典树上的点存储的是字符串
但是本题奇特的方式在在于字典树上存储了两个值
一个是正常的文本串顺序,用于遍历和存储文本串
一个是对于每个句子的答案,有多少个句子可以在这个点回答此答案

最后按照期望DP的方式求解
标程写成递归就直接照搬了,实际上可以写成循环结构

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000 + 5;
struct Node
{
    map<string,int> next;
    map<string,int> answer;
    double pro;
    int tot;
    void clear() {next.clear(); tot = 0; answer.clear();}
}node[MAXN];
char str[MAXN];
double solve(int i, vector<double>::iterator it, int left)
{
//    printf("i = %d\n", i);
    if(left == 0) return 0;
    double ans1 = node[i].pro + *it;
    double ans2 = 0;
    for(auto v : node[i].next) {
        ans2 += solve(v.second, it + 1, left - 1) * node[v.second].tot;
    }
    return max(ans1, ans2 / node[i].tot);
}
int main()
{
    int t, n;
    while(scanf("%d%d", &t, &n) != EOF) {
        cin.getline(str, MAXN);
        int cnt = 0;
        node[cnt].clear();
        for(int j = 0 ; j < n ; j++){
            cin.getline(str, MAXN);
            string temp = "";
            int index = 0;
            string aanswer = "";
            for(int i = strlen(str) - 1 ; i >= 0 ; i--) {
                if(str[i] == ' ') break;
                else aanswer += str[i];
            }
//            cout << " aanswer = " << aanswer << endl;
            node[0].answer[aanswer]++;
            for(int i = 0 ; str[i] != '\0' ; i++){
                if(str[i] != ' ') temp += str[i];
                else{
                    if(node[index].next.count(temp) == 0){
                        node[index].next[temp] = ++cnt;
                        node[cnt].clear();
                    }
                    node[index].tot++;
                    index = node[index].next[temp];
                    node[index].answer[aanswer]++;
                    temp = "";
                }
            }
            node[index].tot++;
//            temp += str[i];
//            if(node[index].next.count(temp) == 0){
//                node[index].next[temp] = ++cnt;
//                node[cnt].clear();
//            }
//            node[index].tot++;
//            index = node[index].next[temp];
//            node[index].tot++;
        }
        for(int i = 0 ; i <= cnt ; i++){
                int mmax = 0;
                int sum = 0;
                for(auto v : node[i].answer) mmax = max(mmax, v.second), sum += v.second;
                node[i].tot = sum;
                node[i].pro = 1.0 * mmax / node[i].tot;
        }
//        for(int i = 0 ; i <= cnt ; i++)
//            printf("i = %d, pro = %f, tot = %d\n", i, node[i].pro, node[i].tot);
        vector <double> best(t + 1);
        for(int i = t - 1 ; i >= 0 ; i--)
            best[i] = solve(0, best.begin() + i + 1, t - i);
        printf("%.10f\n", best[0]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值