zoukankan      html  css  js  c++  java
  • NWERC 2020 部分题解

    NWERC 2020 部分题解

    A. Atomic Energy

    题意

    完全背包,物品的体积是(1,2...n) 价值是(a_1,a_2...a_n)

    给出(q)次询问,每次询问体积恰为(k)的背包的价值是多少

    [1 leq n leq 100,q leq 10^5\ 1 leq a_i leq 10^9,1 leq k leq 10^9 ]

    分析

    发现背包的体积很大,物品的体积很小,能够明显地感觉到应该大范围贪心。

    具体到哪个范围呢?考虑所有物品中性价比最高的物品体积(m),假设最后背包中的物品由体积为(b_1,b_2...)组成,可以得到结论若(size(b) geq m - 1),可以把其中的物品用(m)替换为性价比最高的物品。这是因为大小为(n)的数组,总能找出子集使得和为(n - 1)(简证:对前缀和模n - 1,可以得到n个数至少有一对相同)。于是只需要做背包时把体积上限定为(n imes (m - 1))即可

    代码

    这是赛时代码,事实上上限可以进一步逼近

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    int n, q;
    
    const int N = 110, M = 5e5 + 10;
    ll a[N];
    ll f[M];
    
    int main(){
        memset(f, 0x3f, sizeof f);
        scanf("%d%d",&n,&q);
        double mi = 1e9 + 1;
        int pos = -1;
        for (int i = 1; i <= n; i++) {
            scanf("%lld",&a[i]);
            double x = 1.*a[i] / i;
            if (x < mi) {
                mi = x;
                pos = i;
            }
        }
        assert(pos != -1);
        for (int i = 1; i <= n; i++) {
            f[i] = a[i];
        }
        constexpr int lim = 5e5;
        for (int i = n + 1; i <= lim; i++) {
            for (int j = 1; j <= n; j++) {
                f[i] = min(f[i], f[i - j] + a[j]);
            }
        }
        while (q--) {
            int k;
            scanf("%d",&k);
            if (k <= lim) printf("%lld
    ",f[k]);
            else {
                int y = k - lim;
                int d = (y + pos - 1) / pos;
                long long ans = (long long)d * a[pos];
                k -= d * pos;
                ans += f[k];
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
    

    C.Contest Struggles

    水题

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    
    //d * n = s * k + remain
    
    inline int rd(){
    	int x;
    	scanf("%d",&x);
    	return x;
    }
    
    int main(){
    	int n = rd();
    	int k = rd();
    	int d = rd();
    	int s = rd();
    	double ans = (d * n - s * k) * 1.0 / (n - k);
       	if(ans >= 0 && ans <= 100) 	
    		printf("%lf",(d * n - s * k) * 1.0 / (n - k));
    	else puts("impossible");
    }
    

    D.Dragon Balls

    题意

    在2维平面的第一象限上(包括坐标轴)有(n)个点

    你可以询问至多(1000)次,每次询问给出坐标((x,y)),每次会返回离该点的最近的点的距离的平方

    点的范围(0 leq x leq 10^6,0leq y leq 10^6)

    点的个数(1 leq nleq 7)

    返回的距离(0 leq d leq2 imes 10^{12})

    分析

    尝试每次找原点,这样每次for圆弧上的整点,即可得到点的坐标

    这样的前提是圆弧上的点不会很多,打表得到(r)较大时得到的点的个数不会很多

    注意日经问题:开根号可能会有误差,不妨在map里预处理出所有开方数,每次check一下即可

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    
    //d * n = s * k + remain
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    ll get(int x,int y){
    	printf("%d %d
    ",x,y);
    	fflush(stdout);
    	ll g = rd();
    	return g;
    }
    
    
    int main(){
    	int n = rd();
    	int cnt = 0;
    	map<ll,bool> mp;
    	for(int i = 0;i <= (int)1e6;i++)
    		mp[(ll)i * i] = 1;
    	while(cnt < n){
    		ll d = get(0,0);
    		if(!d) {
    			cnt++;
    			continue;
    		}
    		vector<pair<int,int>> v;
    		for(ll x = 0;x * x <= d;x++){
    			ll y = sqrt(d - x * x);
    			if(!mp.count(d - x * x)) continue;
    			v.push_back(make_pair(x,y));
    		}
    
    		for(int i = 0;i < v.size();i++){
    			ll d = get(v[i].first,v[i].second);
    			if(!d) {
    				cnt++;
    				break;
    			}
    		}
    	}
    }
    

    E.Endgame

    题意

    (n imes n)的棋盘上两人进行移动。每次两人可以选择如下操作之一:1.进行两次给定的移动。2.移动到任意没有棋子的位置3.不移动

    共有(n)个给定移动,负数表示向左或者向上,不能移动到界外

    输出Alice或者Bob或者平局,若平局输出某个情况下的Alice的位置

    (2 leq n leq 10^5)

    分析

    考虑给定的移动只有(n)次移动具有什么性质,得到每次只能移动到至多(n^2/2)个位置

    Alice如果不能在第一次就在两步内移动到Bob,那么Alice不会赢(由于有任意移动的操作)

    所以我们主要考察初始状态即可,再结合(n^2/2)的性质,说明随机在棋盘上选定一个点,它在可以移动的位置的概率最多是(1/2),如果选(k),次,一次都没有选到不可达位置的概率是((1/2)^k) ,因此上随机化就行了(之前的题的思想)

    已知棋盘上两点,如何判断能否在两点内可达。只须考虑(meet in middle)的思想就可以做到(O(nlogn))

    因此如果局面是(tie),就可以在(100)次左右随机到答案,否则输出Bob

    代码

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define eps 1e-9
    #define db long double
    #define equals(a,b) fabs(a-b) < eps
    using namespace std;
    
    typedef long long ll;
    
    
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    const int maxn = 4e5 + 5;
    
    mt19937 rnd(time(0));
    map<pii,bool> mp;
    pii op[maxn];
    int n;
    
    bool ok(int dp,int dv,int p,int v){
    	if(!dp && !dv) return 1;
    	if(mp[make_pair(dp,dv)]) return 1;
    	for(int i = 1;i <= n;i++){
    		int uu = p + op[i].fi;
    		int vv = v + op[i].se;
    		if(uu <= 0 || uu > n || vv <= 0 || vv > n) continue;
    		if(mp[make_pair(dp - op[i].fi,dv - op[i].se)]) return 1;
    	}
    	return 0;
    }
    
    
    int main(){
    	n = rd();
    	int stx,sty;
    	int edx,edy;
    	stx = rd(),sty = rd();
    	edx = rd(),edy = rd();
    	for(int i = 1;i <= n;i++){
    		int dx = rd();
    		int dy = rd();
    		auto p = make_pair(dx,dy);
    		mp[p] = 1;
    		op[i] = p;
    	}
    	if(ok(edx - stx,edy - sty,stx,sty)) {
    		puts("Alice wins");
    		return 0;
    	}
    	int times = 500;
    	while(times--){
    		int i = rnd() % n + 1,j = rnd() % n + 1;
    		if(!ok(i - edx,j - edy,edx,edy)) {
    			printf("tie %d %d
    ",i,j);
    			return 0;
    		}
    	}
    	puts("Bob wins");
    }
    

    F.Flight Collision

    题意

    一维坐标上飞机具有(x_i)坐标和速度(v_i),其中速度是矢量

    若两飞机相遇则会同时消失,问最后留下的飞机的编号

    分析

    观察到性质每次相撞的飞机总是前一时间相邻的飞机

    每次当前局面下第一次相撞的飞机是距离除以相对速度最小的飞机

    因此可以维护当前和后继的相遇时间,每次pop出来后删掉即可

    维护前驱后继可以用链表,也可以用set(因为前驱后继一定有偏序关系)

    实现起来可能有点麻烦,这里用pop需要处理一下之前留下的没用的结点,遇到是时候注意continue掉就好了

    代码

    #include<bits/stdc++.h>
    #define pii pair<db,pair<int,int>>
    #define fi first
    #define se second
    #define eps 1e-9
    #define db long double
    #define equals(a,b) fabs(a-b) < eps
    using namespace std;
    
    typedef long long ll;
    
    
    //d * n = s * k + remain
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    const int maxn = 1e5 + 5;
    
    int x[maxn],v[maxn];
    priority_queue<pii> Q;
    
    void add(int p,int q){
    	if(v[p] <= v[q]) return;
    	db T = (db)(x[p] - x[q]) / (db)(v[p] - v[q]); 
    	Q.push(make_pair(T,make_pair(p,q)));
    }
    
    
    int main(){
    	set<int> s;
    	int n = rd();
    	for(int i = 1;i <= n;i++){
    		x[i] = rd();
    		v[i] = rd();
    		s.insert(i);
    	}
    	for(int i = 1;i < n;i++)
    		add(i,i + 1);
    	while(!Q.empty() && s.size()){
    		auto P = Q.top().se;
    		int i = P.fi;
    		int j = P.se;
    		Q.pop();
    		if(!s.count(j) || !s.count(i)) continue;
    		s.erase(i);
    		s.erase(j);
    		if(!s.size()) break;
    		auto it = s.lower_bound(i);
    		if(it == s.end() || it == s.begin()) continue;
    		int pre = *(--it);
    		int nxt = *s.lower_bound(j);
    		add(pre,nxt);
    	}
    	printf("%d
    ",s.size());
    	for(auto it:s){
    		cout << it << '
    ';
    	}
    }
    

    H.Hot Springs

    题意

    给定(t_1,t_2...t_n)重新排列使得(|t'_{i-1} - t'_{i+1}| leq |t'_i - t'_{i+1}|)

    分析

    这种题图画出来就很容易发现该如何构造了

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    
    //d * n = s * k + remain
    
    inline int rd(){
    	int x;
    	scanf("%d",&x);
    	return x;
    }
    
    int main(){
    	int n = rd();
    	vector<int> v(n);
    	for(int i = 0;i < n;i++){
    		v[i] = rd();
    	}
    	sort(v.begin(),v.end());
    	if(n == 2) {
    		cout << v[0] << ' ' << v[1];
    		return 0;
    	}
    	if(n == 3) {
    		cout << v[1] << ' ' << v[0] << ' ' << v[2];
    		return 0;
    	}
    	vector<int> ans;
    	if(abs(v[0] - v[n - 2]) > abs(v[1] - v[n - 1])) {
    		ans.push_back(n - 1);
    		ans.push_back(0);
    		ans.push_back(n - 2);
    		int l = 1,r = n - 3;
    		for(int i = 0;i < n - 3;i++){
    			if(!(i & 1)) ans.push_back(l++);
    			else ans.push_back(r--);
    		}
    	}
    	else {
    		ans.push_back(0);
    		ans.push_back(n - 1);
    		ans.push_back(1);
    		int l = 2,r = n - 2;
    		for(int i = 0;i < n - 3;i++){
    			if(i & 1) ans.push_back(l++);
    			else ans.push_back(r--);
    		}
    	}
    	reverse(ans.begin(),ans.end());
    	for(auto it:ans){
    		cout << v[it] << ' ';
    	}
    }
    

    I.Island Tour

    队友写的

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int maxn=405;
    int d[maxn];
    int n;
    int t[4][maxn];
    struct node{
        int l,r;
    }s[4][405][405];
    
    vector<int>ab[405];
    vector<int>ac[405];
    vector<int>bc[405];
    
    map<pair<int,int>,int>mp;
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&d[i]);
        }
        for(int j=1;j<=3;j++)
        for(int i=1;i<=n;i++){
            scanf("%d",&t[j][i]);
        }
    
        for(int person=1;person<=3;person++){
            for(int i=1;i<=n;i++){
                int now=1;
                int cnt=0;
                for(int j=i;j<=n;j++){
                    s[person][i][j]=node{now,now+t[person][j]-1};
                    now=now+t[person][j]-1;
                    now=now+d[j]+1;
                }
                for(int j=1;j<i;j++){
                    s[person][i][j]=node{now,now+t[person][j]-1};
                    now=now+t[person][j]-1;
                    now=now+d[j]+1;
                }
            }
            /*
            for(int i=1;i<=n;i++){
                cout<<i<<endl;
                for(int j=i;j<=n;j++){
                    cout<<s[person][i][j].l<<" "<<s[person][i][j].r<<"xxx";
                }
                for(int j=1;j<i;j++){
                    cout<<s[person][i][j].l<<" "<<s[person][i][j].r<<"xxx";
                }
                cout<<endl;
            }
            */
        }
    
    
        // a b
    
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                int kk=1;
                for(int k=1;k<=n;k++){
                    if(!(s[1][i][k].l>s[2][j][k].r||s[2][j][k].l>s[1][i][k].r)){
                        kk=0;
                    }
                }
                if(kk)ab[i].push_back(j);
            }
        }
    
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                int kk=1;
                for(int k=1;k<=n;k++){
                    if(!(s[1][i][k].l>s[3][j][k].r||s[3][j][k].l>s[1][i][k].r)){
                        kk=0;
                    }
                }
                if(kk)ac[i].push_back(j);
            }
        }
    
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                int kk=1;
                for(int k=1;k<=n;k++){
                    if(!(s[2][i][k].l>s[3][j][k].r||s[3][j][k].l>s[2][i][k].r)){
                        kk=0;
                    }
                }
                if(kk)bc[i].push_back(j);
            }
        }
    
        /*
        for(int i=1;i<=n;i++){
            for(auto x:ab[i]){
                cout<<i<<" "<<x<<endl;
            }
        }
    
        for(int i=1;i<=n;i++){
            for(auto x:ac[i]){
                cout<<i<<" "<<x<<endl;
            }
        }
    
        for(int i=1;i<=n;i++){
            for(auto x:bc[i]){
                cout<<i<<" "<<x<<endl;
            }
        }
    
    
        */
        for(int i=1;i<=n;i++){
            for(auto x:bc[i]){
                mp[{i,x}]=1;
            }
        }
    
        for(int i=1;i<=n;i++){
            for(auto x:ab[i]){
                for(auto y:ac[i]){
                    if(mp[{x,y}]){
                        cout<<i<<" "<<x<<" "<<y<<endl;
                        return 0;
                    }
                }
            }
        }
        cout<<"impossible";
    }
    

    K.Keyboardd

    水题

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    
    //d * n = s * k + remain
    
    inline int rd(){
    	int x;
    	scanf("%d",&x);
    	return x;
    }
    
    map<char,int>mp;
    int main(){
    	string s,t;
    	getline(cin,s);
    	getline(cin,t);
    	int now=1;
    	int p=0;
    	for(int i=1;i<t.size();i++){
            if(t[i]==t[i-1]){
                now++;
            }else{
                int pp=0;
               for(int j=p;j<s.size();j++){
                 if(s[j]==t[i-1])pp++;
                 else {
                    p=j;
                    break;
                 }
               }
               if(pp==now){
                 now=1;
               }else{
                 if(mp[t[i-1]]!=1)cout<<t[i-1];
                 mp[t[i-1]]=1;
                 now=1;
                }
            }
    	}
    
    	if(now!=(s.size()-p)){
            if(mp[s[p]]!=1)cout<<s[p];
    	}
    }
    
  • 相关阅读:
    Sandcastle 这个工具生成文档不错
    Windows 服务关闭自动重启
    『录』最全前端资源汇集
    利用Continuous Testing实现Eclipse环境自动单元测试
    (转载)const指针和指向const的指针(左值右指)
    为什么寄存器比内存快?
    Vim Buffer
    Linux操作系统文件系统基础知识详解(引用内容)
    详解BOM头以及去掉BOM头的方法
    对比MySQL,什么场景MongoDB更适用
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14999406.html
Copyright © 2011-2022 走看看