2017 Multi-University Training Contest - Team 2

1001:

首先,我们统计出Derek和Alfia答案相同的题目数量k1和答案不同的题目数量k2. 对于两人答案相同的题目,共有以下两种情况:

  • 两人都对

b.两人都错 对于两人答案不同的题目,共有以下三种情况: c.Derek对Alfia错 d.Alfia对Derek错 e.两人都错 于是我们可以列出一些方程: k1+k2=n a+b=k1 c+d+e=k2 a+c=x a+d=y 又a,b,c,d,e均为非负整数,且满足a,b<=k1;c,d,e<=k2 将a,b,d,e全部用c替换后需要同时满足以下四个条件: 0<=c<=k2 x-y<=c<=k2+x-y (x-y)/2<=c<=(k2+x-y)/2 x-k1<=c<=x 我们只需要判断这四段区间存不存在公共的整数点,如果存在,则说明Derek没有说谎;如果不存在,则说明Derek在说谎。

#include <iostream>  
#include <cstdio>  
#include <cstring>  
#include <queue>  
#include <cmath>  
#include <algorithm>  
#include <deque>  
using namespace std;
typedef long long ll;
const int INF = 2147483640;
const int maxn = 80000 + 100;
const int maxm = 200000;
char ar[maxn], sa[maxn];
int main()
{
int i, j, k, u, n, m, A, B, N;
while (scanf("%d", &n) != EOF)
{
for (m = 1; m <= n; m++)
{
int doudou1 = 0;
int doudou2 = 0;
scanf("%d %d %d", &N, &A, &B);
scanf("%s", ar);
scanf("%s", sa);
for (i = 0; i < N; i++)
{
if (ar[i] == sa[i])
doudou1++;
else
doudou2++;
}
if (A + B <= (doudou2 + doudou1 * 2) && doudou2 >= abs(A - B))
printf("Not lying\n");
else
printf("Lying\n");
}
}
return 0;
}

1003:

预处理:a_i -= i ,易证明从最小的b开始选每次选最大的一定可以使结果最大。 证明思路:如果条件改为a_i<=max{a_j-j|b_k<=j<=n},那么b的顺序与最后的结果无关。条件改回来后,由于每次要计算一个数的最大值时都有a_(n+1)...a_(i-1)在范围中,所以每次只需让a_i - i尽可能大,那么就把大的数尽早用上,每次一定考虑尽量多的数字,这样取得的数字就尽可能的大。 所以说每次就是求区间最值,加在答案上。由于贪心的思路,每次要求的区间的下界是单调不降的,故可以用单调队列优化到O(n)的复杂度。 由于1 ≤ b_i ≤ n,对b排序可以用哈希排序(桶排序)完成。 进一步观察,可以发现这样贪心时 a_(n+1)...a_i 其实是单调不增的,所以并不需要每次求区间最值了,选第一个数时就选最大的,后面的选择顺序与最终结果无关了。

#include <bits/stdc++.h>


using namespace std;


typedef long long ll;
const ll MOD = 1e9+7;
int a[300000];
int b[300000];


struct node{
    int a,id;
};


struct cmp{
    bool operator ()(const node &a,const node &b){
        return a.a<b.a;
    }
};


priority_queue< node ,vector<node > ,cmp> Q;


int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i=1;i<=n;i++)
            scanf("%d",a+i);
        for(int i=1;i<=n;i++)
            scanf("%d",b+i);
        for(int i=1;i<=n;i++)
            a[i]-=i;
        int tmx = a[n];       
        while(!Q.empty()) Q.pop();
        sort(b+1,b+1+n);
        ll ans = 0;
        for(int i=1;i<=n;i++){
            Q.push(node{a[i],i});    
        }
        int t=0;
        for(int i=n+1;i<=n+n;i++){
            while(Q.top().id<b[i-n]) Q.pop();
            node now = Q.top();
            ans += now.a;
            ans %= MOD;
            Q.push(node{now.a-i,i});
        }
        cout<<ans<<endl;
    }
    return 0;
}

1006:

对于任意i>=1,当j>=3时,有 1 通过归纳法可以得到 2 进而推导出 3 通过矩阵快速幂求解

1011:

题意,二维平面上给N个整数点,问能构成多少个不同的正多边形。 题解:容易得知只有正四边形可以使得所有的顶点为整数点。(具体证明可参考杨景钦在2017的国家队论文) 所以正解即求出所有的正四边形个数。 枚举2个点,然后暴力判断另外2个点的位置是否存在。 复杂度 N*N*logN。


#include <bits/stdc++.h>


using namespace std;


struct node{
    int x,y;
}info[1000];


int mp[402][402];


int p[402][402];


int main(){
    int n;
    while(~scanf("%d",&n)){
        memset(mp,0,sizeof mp);
        memset(p,0,sizeof p);
        int mx=0,my=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d",&info[i].x,&info[i].y);
            info[i].x+=100;
            info[i].y+=100;
            mp[info[i].x][info[i].y]=1;
        }
        int ans = 0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++){
                if(info[i].x>=info[j].x || info[i].y>=info[j].y) continue;
                int nx = info[i].x;
                int ny = info[i].y;
                int l  = info[j].x - nx;
                int s  = info[j].y - ny;
                if(l==s && mp[nx+l][ny] && mp[nx][ny+s] && mp[nx+l][ny+s]){
                    ans++;
                }
                int sx = nx - (info[j].y - ny);
                int sy = ny + (info[j].x - nx);
                int tx = sx + (info[j].x - nx);
                int ty = sy + (info[j].y - ny);
                if(mp[sx][sy] && mp[tx][ty]){
                    ans++;
                }
            }
        cout<<ans<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值