2019icpc西安邀请赛

来源:https://www.jisuanke.com/contest/2625?view=challenges

更新中

A.Tasks

直接贪心

代码:听说当时很多队伍提前拆题甚至上机了,所以很多0min

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
     
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
 
using namespace std;
 
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
 
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e6+100;
const int maxm = 6e6+100;
//const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int MAXN = maxn;
const int MAXM = maxm;
const db pi = acos(-1.0);

int n, t;
int a[maxn];
int main() {
    scanf("%d %d" ,&n ,&t);
    for(int i = 0; i < n; i++){
        scanf("%d", &a[i]);
    }
    sort(a,a+n);
    int tmp = 0;
    int ans = 0;
    for(int i = 0; i < n; i++){
        if(tmp+a[i]<=t){
            tmp+=a[i];ans++;
        }

    }printf("%d", ans);
    return 0;
}
View Code

C.Angel's Journey

题意:给定一个圆的圆心(rx, ry),半径r,A的坐标(rx, ry-r),B的坐标(x, y),y>ry,只能走圆上以及圆外y>ry的地方,求A到B的最短路

思路:当x<rx-r或x>rx+r的时候直接从半圆的地方走直线,否则在圆弧上走到切点然后走直线

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
     
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
 
using namespace std;
 
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
 
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e6+100;
const int maxm = 6e6+100;
//const int inf = 0x3f3f3f3f;
const int INF = 0x3f3f3f3f;
const int MAXN = maxn;
const int MAXM = maxm;
const db pi = acos(-1.0);

int n, t;
int a[maxn];
int main() {
    double rx,ry,r,x,y;
    int t;
    scanf("%d" ,&t);
    while(t--){
        scanf("%lf %lf %lf %lf %lf", &rx,&ry,&r,&x,&y);

        double ob = sqrt((x-rx)*(x-rx)+(y-ry)*(y-ry));
        double ans = sqrt(ob*ob-r*r)+r*(pi/2.0+asin((y-ry)/ob)-acos(r/ob));
        if(x<rx-r||x>rx+r){
            if(x<rx-r)rx-=r;
            if(x>rx+r)rx+=r;
            ans=pi/2+sqrt((x-rx)*(x-rx)+(y-ry)*(y-ry));
        }
        printf("%.4lf\n",ans);
    }
    return 0;
}
View Code

D.Miku and Generals

题意:n个数,还有m对矛盾的数,n,m<=200,a[i]<=5e4&&(a[i]%100==0),矛盾的不能放在一堆,让你分配这两堆数(都要用完),使得两堆数的和之差最小,输出那个最大的数

思路:将矛盾的值连无向边,因为答案是保证存在的,所以对每一个连通块只有两种选法,通过dfs染色把它们提出来,就是一个背包了,由于a[i]%100==0,所以先除了最后再补俩零也不影响

代码:我tm最后才发现那个a[i]能整除100。。复杂度downdown

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
     
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
 
using namespace std;
 
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
 
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e7+100;
const int maxm = 6e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int n, m;
vector<int>v[maxn/100];
int vis[maxn/100];
int a[maxn/100];
int f[maxn];

void dfs(int x, int fa, int faa, int co){
    if(vis[x]!=-1)return;
    if(co){
        if(x!=fa){a[fa]+=a[x];a[x]=-1;}
        vis[x]=fa;
    }
    else{
        if(x!=faa){a[faa]+=a[x];a[x]=-1;}
        vis[x]=faa;
    }
    int t;
    if(x==fa&&v[x].size()>0)t = v[x][0];
    else t=faa;
    for(int i = 0; i < (int)v[x].size(); i++){
        int y = v[x][i];
        if(vis[y]==-1){
            dfs(y,fa,t,co^1);
        }

    }
}
bool cmp(int a,int b){return a>b;}
int main() {
    int t;
    scanf("%d" ,&t);
    int ncase = 0;
    while(t--){
        scanf("%d %d" ,&n, &m);
        //mem(f,0);
        ncase++;
        int sum = 0;
        for(int i = 1; i <= n; i++){
            v[i].clear();
            vis[i]=-1;
            scanf("%d", &a[i]);a[i]/=100;sum+=a[i];
        }
        for(int i = 1; i <= m; i++){
            int x,y;
            scanf("%d %d" ,&x, &y);
            v[x].pb(y);
            v[y].pb(x);
        }
        for(int i = 1; i <= n; i++){
            if(vis[i]==-1){
                dfs(i,i,0,1);
            }
        }
        sort(a+1,a+1+n,cmp);
        int ans=0;
        f[0]=ncase;
        for(int i = 1; i <= n; i++){
            if(a[i]==-1)break;
            for(int j = sum; j >= 0; j--){
                if(j-a[i]>=0&&f[j-a[i]]==ncase){
                    //printf("  %d  \n",j);
                    f[j]=ncase;
                    if(j<=sum/2)ans=max(ans,j);
                }
            }
        }
        printf("%d00\n",sum-ans);
    }
    
    return 0;
}
 
View Code

J.And And And

题意:一棵有边权的树,对每一对(u,v),如果u到v路径上边权异或和为0,则它对答案的贡献为包含这条路径的树上路径数量,求总答案

思路:以1为根,预处理出各个子树的size,对每一对满足条件的(u,v),因为树上的路径是唯一的,它的贡献应该是u除这条路径外能走的点数*v除这条路径外能走的点数,当u和v在不同链上的时候,答案就是size[u]*size[v];若u和v在同一条链上,其中一个点(例如v)如果是深度较大的点,那么后者就是size[v],前者可以动态统计。

于是可以直接dfs,因为dfs的时候走下来就是一条链,回溯之后就是另一条链,所以在处理同一条链的时候我们可以统计当前点为u时的贡献即可。不同链的时候,我们让它dfs到底,当当前点处理完之后,说明这条链搞完了,就可以一条链一条链更新了,这个看代码好像比较好理解。。。

对了,u到v路径异或和为0可以转化为到根的异或和相等。

代码:long long很烦,而且深搜好像并不需要记录fa。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
#include<unordered_map>
     
#define fst first
#define sc second
#define pb push_back
#define mp make_pair
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
 
using namespace std;
 
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
 
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e5+100;
const int maxm = 6e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int n;
vector<pair<int,ll> >v[maxn];
int sz[maxn];
void dfsInit(int x, int fa){
    sz[x]++;
    for(int i = 0; i < (int)v[x].size(); i++){
        int y = v[x][i].fst;
        if(y!=fa){
            dfsInit(y,x);
            sz[x]+=sz[y];
        }
    }
}
ll ans;
unordered_map<ll,int> num;// the value of gongxian in sta == i
ll tmp;
void dfs1(int x, int fa, ll sum){//the same line
    ans += 1ll*num[sum]*sz[x];
    ans%=mod;
    for(int i = 0; i < (int)v[x].size(); i++){
        int y = v[x][i].fst;
        ll w = v[x][i].sc;
        if(y!=fa){
            tmp=(tmp+sz[x]-sz[y]+mod)%mod;
            num[sum]=(num[sum]+tmp)%mod;
            dfs1(y,x,sum^w);
            num[sum]=(num[sum]-tmp+mod)%mod;
            tmp=(tmp-(sz[x]-sz[y])+mod)%mod;
        }
    }
}
void dfs2(int x, int fa, ll sum){
    ans += 1ll*num[sum]*sz[x];
    ans%=mod;
    for(int i = 0; i < (int)v[x].size(); i++){
        int y = v[x][i].fst;
        ll w = v[x][i].sc;
        if(y==fa)continue;
        dfs2(y,x,sum^w);
    }
    num[sum]+=sz[x];
    num[sum]%=mod;
}
int main() {
    tmp=ans=0;
    scanf("%d" ,&n);
    for(ll i = 2; i <= n; i++){
        int x;
        ll w;
        scanf("%d %lld", &x, &w);
        v[x].pb(mp(i,w));
        v[i].pb(mp(x,w));
    }
    dfsInit(1,0);
    dfs1(1,0,0);
    num.clear();
    dfs2(1,0,0);
    printf("%lld",ans);
    return 0;
}
View Code

L.Swap

题意:一个排列可以交换前n/2与后n/2,或前n^1个数奇数位置和偶数位置交换,问通过这两个操作最多产生多少个不同的排列

思路:打表发现从第五项开始是2n, n, 12, 4的规律。或者直接交上打表的模拟,由于只有两条链,而且只有一组数据,也能过

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
     
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
 
using namespace std;
 
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
 
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e6+100;
const int maxm = 6e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int n;
int a[maxn],b[maxn];
int ans;
void gao1(int a[]){
    int l = 1;
    int r = n/2+1;
    if(n&1)r++;
    for(int i = 1; i <= n/2; i++){
        swap(a[l+i-1],a[r+i-1]);
    }
    return;
}
void gao2(int a[]){
    for(int i = 1; i+1 <= n; i+=2){
        //printf("  %d %d %d\n",i,a[i],a[i+1]);
        swap(a[i],a[i+1]);
    }
    return;
}

int sv(int n){
    ::n=n;
    ans=1;
    int sta=1;
    for(int i = 1; i <= n; i++)a[i]=b[i]=i;
    /*if(n==1)return 1;
    if(n==2)return 2;
    if(n==3)return 6;*/
    gao1(a);gao2(b);
    //for(int i = 1; i <= n; i++)printf("%d ",a[i]);printf("\n");
    //for(int i = 1; i <= n; i++)printf("%d ",b[i]);printf("\n");
    while(1){
        //for(int i = 1; i <= n; i++)printf("%d ",a[i]);printf("\n");
        //for(int i = 1; i <= n; i++)printf("%d ",b[i]);printf("\n");
        int ys = 0;
        sta^=1;
        for(int i = 1; i <= n; i++){
            if(a[i]!=b[i])ys=1;
        }
        if(!ys){
            ans++;break;
        }
        else{
            ans+=2;
            if(sta) {gao1(a);gao2(b);}
            else {gao1(b);gao2(a);}
        }
    }
    return ans;
}
int main() {
    //scanf("%d" ,&n);
    //sv(3);
    for(int i = 1; i <= 100; i++){
        printf("%d %d\n",i,sv(i));
    }
    scanf("%d", &n);
    //for(int i = 1; i <= n; i++)scanf("%d", &a[i]);
        printf("%d",sv(n));
    return 0;
}
View Code

 M.Travel

题意:一个有边权的无向图,刚开始无边可走,每次操作可以增加e条边,增加d点能量,每次操作花费c,问从1走到n最少花费多少,只有这条边加了并且能量不小于边权才能走

思路:我第n次sb。。很明显的二分,而我妄图一次dijk搞完,就把自己搞完了。

很显然操作次数具有单调性,并且因为保证联通,所以答案一定存在。

代码:因为改了很多次,所以很丑

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<stack>
#include<queue>
#include<deque>
#include<set>
#include<vector>
#include<map>
#include<functional>
     
#define fst first
#define sc second
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,root<<1
#define rson mid+1,r,root<<1|1
#define lc root<<1
#define rc root<<1|1
#define lowbit(x) ((x)&(-x))
 
using namespace std;
 
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PI;
typedef pair<ll,ll> PLL;
 
const db eps = 1e-6;
const int mod = 1e9+7;
const int maxn = 1e6+100;
const int maxm = 6e6+100;
const int inf = 0x3f3f3f3f;
const db pi = acos(-1.0);

int vis[maxn];
struct node{
    int id,w;
    node(int a, int b){id=a;w=b;}
    bool operator < (const node & a) const{
        return w>a.w;
    }
};
vector<node>v[maxn];
int n,m;
int c, d, e;
bool ck(int k){
    //printf(" %d\n",k);
    for(int i = 1; i <= n; i++)vis[i]=0;
    queue<PI>q;
    q.push(make_pair(1,0));
    while(!q.empty()){
        PI top = q.front();q.pop();
        int x = top.fst;
        int d = top.sc;
        //printf("%d %d  ----%d\n",x,d);
        if(x==n){
            if(d<=1ll*e*k)return true;
            else return false;
        }
        if(vis[x])continue;
        vis[x]=1;
        for(int i = 0; i < (int)v[x].size(); i++){
            node y = v[x][i];
            //printf("  %d %d\n",y.id,y.w);
            if(!vis[y.id]&&1ll*y.w<=1ll*(::d)*k)q.push(make_pair(y.id,d+1));
        }
    }
    return false;
}
int main() {
    
    scanf("%d %d", &n, &m);
    scanf("%d %d %d" ,&c, &d, &e);
    for(int i = 1; i <= m; i++){
        int x,y,w;
        scanf("%d %d %d" ,&x, &y, &w);
        v[x].pb(node(y,w));
        v[y].pb(node(x,w));
    }
    int l, r;
    l = 0; r = 1e5+100;
    int ans = -1;
    while(l<=r){
        int mid = (l+r)>>1;
        if(ck(mid)){
            ans = mid;
            r=mid-1;
        }
        else l= mid+1;
    }
    printf("%lld",1ll*c*ans);
    return 0;
}
/*
3 3
1 99 1 
1 2 100
1 3 100
2 3 2
 */
View Code

 

posted @ 2019-06-03 20:56  wrjlinkkkkkk  阅读(638)  评论(0编辑  收藏  举报