2020.2.22 寒假大一2.22考试

Problem A:NEFU2122 熊熊对对碰

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
map<pair<int, int>, int> a;
pair<int, int> p;
int main()
{
    int n;
    //ios::sync_with_stdio(false);
    scanf("%d", &n);
    while(n--)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        if(a.count({-1*x, -1*y})) a[{-1*x, -1*y}]++;
        else a[{x, y}]++;
    }
    int cnt=0;
    for(map<pair<int, int>, int>::iterator it=a.begin(); it!=a.end(); it++)
    {
        if(!(it->second%2))
            cnt += it->second;
    }
    printf("%d\n", cnt);
    return 0;
}

Problem B:NEFU2120 秘籍

这题一看就是前缀和嘛,正好前一天写了一篇博客 然后打了暴力,吸氧水过去了。代码就不贴了。

贴一下尺取法的代码:

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int n, k, a[300010];
int l, r;
bool check()
{
    int tmp = 0;
    l = 1;
    for(r=1; r<=n; r++)
    {
        tmp += a[r];
        while(tmp>k && l<r)
        {
            tmp -= a[l];
            l++;
        }
        if(tmp==k) return 1;
    }
    return 0;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>k;
    for(int i=1; i<=n; i++)
        cin>>a[i];
    if(check()) cout<<l<<" "<<r<<endl;
    else cout<<"tiangeniupi"<<endl;
    return 0;
}

Problem C:NEFU2103 jwGG的签到题

打表找规律题,这真不是签到题。(我的签退题)

先暴力打表到1e4或1e5

int line(int x, int y)
{
    int tmp=y;
    while(tmp)
    {
        tmp /= 10;
        x *= 10;
    }
    return x+y;
}
int main()
{
    for(int a=1; a<=1000; a++)
        for(int b=1; b<=10000; b++)
        if(a*b == line(a, b)-a-b)
            printf("%d %d\n", a, b);
    
    return 0;
}

找出规律:只与y有关且y只能为9,99,999……

然后即可根据表写出代码

typedef long long ll;
int t;
ll num[18] = {9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999, 9999999999999999, 99999999999999999, 999999999999999999}; 
int main()
{
    scanf("%d", &t);
    for(int mcv=1; mcv<=t; mcv++)
    {
        unsigned long long a, b, cnt=0;
        scanf("%llu%llu", &a, &b);
        //int i;
        for(int i=0; i<18; i++)
        {
            if(num[i]<=b)
                cnt++;
            else
            {
                //printf("%llu\n", cnt*a);
                break;
            }
        }
        cnt *= a;
        printf("%llu\n", cnt);
    }
    return 0;
}

Problem D:NEFU2133 jwMM的疯狂A-B

这才是签到题,纯set做就可以了。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int n, m;
int x;
set<int> a, b;
int main()
{
    ios::sync_with_stdio(false);
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++)
    {
        scanf("%d", &x);
        a.insert(x);
    }
    for(int i=1; i<=m; i++)
    {
        scanf("%d", &x);
        b.insert(x);
    }
    int cnt=0;
    for(set<int>::iterator it=a.begin(); it!=a.end(); it++)
    {
        if(!b.count(*it))
        {
            printf("%d\n", *it);
            cnt++;
        }
    }
    if(!cnt) printf("So crazy!!!\n");
    return 0;
}

Problem E:NEFU2126 煊哥的难题

好难啊。

Li与Lj至少有一个公共点:相交或重合

i 从 1 到 n 遍历所有直线,每次 ans 都加上 i - 1 - 平行Li的个数。

需要特判直线垂直于x轴的情况

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
map<double, int> kis; // 斜率相等
map<double, map<double, int> > kbis; // 重合
map<double, int> vertx; // 垂直于x轴
int main()
{
    ios::sync_with_stdio(false);
    int n, x1, y1, x2, y2, x0=0;
    long long ans = 0;
    cin>>n;
    for(int i=1; i<=n; i++)
    {
        cin>>x1>>y1>>x2>>y2;
        if(x1==x2) // 垂直于x轴
        {
            int num = x0-vertx[x1*1.0]; // 平行
            ans += i-1-num;
            x0++; // 平行或重合
            vertx[x1*1.0]++; // 重合
        }
        else
        {
            int x=x1-x2, y=y1-y2;
            double k = y*1.0/x;
            double b = y1*1.0-k*x1;
            int num = kis[k]-kbis[k][b]; // 平行
            ans += i-1-num;
            kis[k]++; // 平行或重合
            kbis[k][b]++; // 重合
        }
    }
    cout<<ans<<endl;
    return 0;
}

Problem F:NEFU2106 jwGG与yzMM的字符串

直到听了题解才知道怎么能在有取模操作的情况下解密。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
struct node{
    int x, y;
}pass[100010];
char a[52], str[1010][1010], ans[130][130];
void init()
{
    for(int i=0; i<52; i++)
    {
        if(i<26) a[i] = i+'A';
        else a[i] = i+'a'-26;
        //cout<<a[i]<<" ";
    }
    for(int i=0; i<52; i++)
        for(int j=0; j<52; j++)
        {
            int z = (i+j)%52;
            ans[a[j]][a[z]] = a[i];
        }
}
int main()
{
    ios::sync_with_stdio(false);
    int n, m, xi, yi;
    cin>>n>>m;
    init();
    for(int i=1; i<=m; i++)
        cin>>pass[i].x>>pass[i].y;
    for(int i=1; i<=n; i++)
        cin>>str[i];
    for(int i=m; i>=1; i--) // 解密-倒序
    {
        int xi=pass[i].x, yi=pass[i].y;
        int l1=strlen(str[xi]), l2=strlen(str[yi]);
        for(int j=0; j<l2; j++)
            str[yi][j] = ans[str[xi][j%l1]][str[yi][j]];
    }  
    for(int i=1; i<=n; i++)
        cout<<str[i]<<endl;
    return 0;
}

Problem G:NEFU2107 jwGG与bwMM的字符串

对于字符串前缀的介绍可以参考此博客kmp部分。当然此题要求空串也算前缀。

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
string str;
int t;
int check[100010];
int main()
{
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--)
    {
        int n, x;
        cin>>n>>x;
        cin>>str;
        int cnt0=0, cnt1=0, ans=0;
        if(!x) ans++; // 空串也是前缀
        bool flag = false;
        for(int i=0; i<n; i++) //得到0和1的个数
        {
            if(str[i]-'0') cnt1++;
            else cnt0++;
            check[i] = x+cnt1-cnt0; // 预处理x与num(pre,0)-num(pre,1)的关系
        }
        if(cnt0==cnt1) // 只有0和1的数目相等时才会出现无数个等于x的平衡系数
            for(int i=0; i<n; i++)
            {
                if(!check[i])
                {
                    flag = true;
                    break;
                }
                else continue;
            }
        else
            for(int i=0; i<n; i++)
                if(check[i]%(cnt0-cnt1)==0 && check[i]/(cnt0-cnt1)>=0)
                    ans++; 
        if(flag) cout<<-1<<endl;
        else cout<<ans<<endl;
    }
    return 0;
}

Problem H:NEFU2123 库特放书

出题人gls解释了为什么直接暴力不会超时:

H题再解释一下为什么直接暴力不用二分在时间上是可行的吧,因为我看所有通过代码都写的枚举容量的上界是sum,但是如果上界真的是sum的话在时间上理论上是不可行的,这一点上并不是我数据出水了,是它的下界可以视为max(ceil(sum / k),maxV),上界为ceil(sum / k)+MAXV
所以枚举次数为二者之差远达不到sum次,最多也不会超过1000次所以从下界while(1)向上寻找在时间上是可行的

//#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
int t, n, m;
int v[1005];
bool box[1005];
bool put(int vol)
{
    fill(box, box+1005, 0);
    for(int i=1; i<=m; i++)
    {
        int tmp=0;
        for(int j=1; j<=n; j++)
            if(tmp+v[j]<=vol && !box[j])
            {
                box[j] = 1;
                tmp += v[j];
            }
    }
    for(int i=1; i<=n; i++)
        if(!box[i]) return 0;
    return 1;
}
int main()
{
    ios::sync_with_stdio(false);
    scanf("%d", &t);
    for(int mcv=1; mcv<=t; mcv++)
    {
        int sum=0, tmp;
        scanf("%d%d", &n, &m);
        for(int i=1; i<=n; i++)
        {
            scanf("%d", &v[i]);
            sum += v[i];
        }
        sort(v+1, v+n+1);
        reverse(v+1, v+n+1);
        for(int i=sum/m; i<=sum; i++)
            if(put(i))
            {
                tmp = i;
                break;
            }
        printf("Case #%d: %d\n", mcv, tmp);
    }
    return 0;
}
发布了65 篇原创文章 · 获赞 50 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/baidu_41248654/article/details/104477113