ICPC 2019-2020 North-Western Russia Regional Contest

B. Bad Treap
我的思路有问题,这道题其实本质是找一个递增序列,其对应的函数sin也是递增的,一开始我打算从三角函数的周期入手,找一个最接近2PI的n值,把它当周期,使得sin值变化更小;
结果就是找不到;
其实三角函数变化率还是挺大的,这就意味着即使较小的变化也会导致数值变化更大;
正确思路是找一个最小的正的sinx,这样对应的x即使变化很大,但由于sin值很小,sin值也不会有太大的波动

#include 
#define P pair
using namespace std;

vector <P> v;
vector <int> xs;

int main(){
    int n;
    cin>>n;
    for(int i=1;i<=50000;i++){
        if(sin(i)>0) v.push_back({sin(i),i});
    }
    /*
    for(vector 

::iterator it=v.begin();it!=v.end();it++){ cout<first<<" "<second< sort(v.begin(),v.end()); int temp=v[0].second; for(int i=-25000;i<=25000;i++){ xs.push_back(temp*i); } for(int i=0;i<n;i++) cout<<xs[i]<<endl; return 0; }

E. Equidistant
一道比较简单的dfs的题
思路是首先从一个队伍开始dfs所有结点,找到所在结点最深的队伍,那么所要求的城市一定在两个结点中间,这里dfs不光要求起点到每个结点的距离,还要记录父亲结点的位置,这样就可以从最深的结点出发,回溯去找距离为起点和终点中间的那个城市,找到的城市就是答案,这里还不能保证该节点到所有队伍距离相等,所以还要dfs一次,如果这次答案到每个队伍距离相等,就可以确定答案是正确的;

#include 
using namespace std;
const int MAXN=2e5+100;
vector <int> adj[MAXN];
int teams[MAXN];
int father[MAXN];
int dis[MAXN];
int n,m;
int u,v;

void dfs(int x,int fa){
    father[x]=fa;
    dis[x]=dis[fa]+1;
    for(vector<int>::iterator it=adj[x].begin();it!=adj[x].end();it++){
        if(*it==fa) continue;
        dfs(*it,x);
    }
}

int main(){
    cin>>n>>m;
    for(int i=0;i<n-1;i++){
        cin>>u>>v;
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    for(int i=1;i<=m;i++){
        cin>>teams[i];
    }
    if(m==1){
        printf("YES\n");
        printf("1\n");
        return 0;
    }
    dfs(teams[1],0);
    int key=teams[2];
    for(int i=2;i<=m;i++){
        if(dis[teams[i]]>dis[key]) key=teams[i];
    }
    if((dis[teams[1]]+dis[key])&1){
        printf("NO\n");
        return 0;
    }
    int ans=(dis[teams[1]]+dis[key])>>1;
    int x=key;
    while(dis[x]!=ans){
        x=father[x];
    }
    dfs(x,0);
    for(int i=2;i<=m;i++){
        if(dis[teams[i]]!=dis[teams[i-1]]){
            printf("NO\n");
            return 0;
        }
    }
    cout<<"YES"<<endl;
    cout<<x<<endl;
    return 0;
}

H. High Load Database
这道题看了很久才明白到底是什么意思;
大概就是将数分成连续的几组,然后让每组最大值不超过所给的t,问最少可以分几组;
白痴做法是每给一个t都去遍历一遍an,这样复杂度为O(qn)
所以会爆一点都不意外;
解决技巧主要是靠前缀和和二分,我们先将所给的an的前缀和都求出来,这样只要找到连续的几项,相差<=k就可以了,找前缀和的时候,再使用二分法复杂度就大大降低了;
另外就是用一个数组来存储对应k值的答案,这样如果前面算过,就不用重复计算了

#include 
using namespace std;

int main(){
    int n;
    cin>>n;
    vector <int> a(n);
    for(int i=0;i<n;i++) cin>>a[i];
    int sum=0;
    int MAX=-1;
    for(int i=0;i<n;i++){
        sum+=a[i];
        MAX=max(MAX,a[i]);
    }
    int q;
    cin>>q;
    vector <int> b;
    b=a;
    for(int i=1;i<n;i++) b[i]+=b[i-1];
    vector <int> ans(sum+1,-1);
    for(int i=0;i<q;i++){
        int k;
        cin>>k;
        if(k<MAX){
            cout<<"Impossible"<<endl;
            continue;
        }
        if(ans[k]<0){
            int cur=0;
            int curAns=0;
            int ah=0;
            while(cur<n){
                int left=cur-1;
                int right=n;
                while(left<right-1){
                    int mid=(left+right)>>1;
                    if(b[mid]-ah>k){
                        right=mid;
                    }else{
                        left=mid;
                    }
                }
                ah=b[left];
                cur=left+1;
                curAns++;
            }
            ans[k]=curAns;
        }
        cout<<ans[k]<<endl;
    }
}

你可能感兴趣的:(icpc)