Codeforces Round #158 (Div. 2)

这场的模拟题真的有du!!!

Problem A

水题,更新当前对b取模后的余数,直接模拟。

#include<bits/stdc++.h>
using namespace std;
const int N=2*1e5;
int a,b,n;
char s[N];
int main()
{
    scanf("%d%d%d",&a,&b,&n);
    int now=a%b;
    bool flag=true;
    int pos=0;
    for(int i=1;i<=n;i++)
    {
        bool judge=false;
        for(int j=9;j>=0;j--)
        {
            if(((now*10)+j)%b==0)
            {
                judge=true;
                now=0;
                s[pos++]='0'+j;
                break;
            }
        }
        if(!judge) flag=false;
    }
    s[pos]=0;
    if(flag) printf("%d%s\n",a,s);
    else puts("-1");
    return 0;
}
View Code

Problem B

看到第一眼,我不想做了!直接跳到了第三题,其实还好,做完第三题后一发就A了。

题目大意:给你一串字符串,让你找出出现次数最多的日期,形式 xx-yy-zzzz,且年份

在2013-2015之间。

 

思路:我的写法是开一个vis[6][13][32]的数组记录日期出现过的次数,最后找出最大

的一个就好了。在找的时候我先找的中间的月份,在向前向后延伸找,其实是可以直接

十个字符十个字符找,更简单一点。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+3;
const int d_m[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
char s[N];
int vis[6][13][32],len;
void work(int x,int y,int m)
{
    if(x<=0 || y>len) return;
    if(s[x]!='-' && s[x+1]!='-')
    {
        int now=10*(s[x]-'0')+(s[x+1]-'0');
        if(now<=d_m[m])
        {
            if(s[y-3]=='2' && s[y-2]=='0' && s[y-1]=='1' && s[y]>='3' && s[y]<='5')
                vis[s[y]-'0'][m][now]++;
            else return;
        }
        else return;
    }
    else return;
}
int main()
{
    scanf("%s",s+1);
    len=strlen(s+1);
    for(int i=1;i+3<=len;i++)
    {
        if(s[i]=='-' && s[i+3]=='-' && ((s[i+1]=='0' && s[i+2]>='1' && s[i+2]<='9') || (s[i+1]=='1' && s[i+2]>='0' && s[i+2]<='2')))
        {
            //printf("%d %c^^^^^\n",i,s[i]);
            int m=10*(s[i+1]-'0')+(s[i+2]-'0');
            work(i-2,i+7,m);
        }
    }
    int ansv=0,ansy=0,ansm=0,ansd=0;
    for(int i=3;i<=5;i++)
    {
        for(int j=1;j<=12;j++)
        {
            for(int k=1;k<=d_m[j];k++)
            {
                if(vis[i][j][k]>ansv)
                {
                    ansv=vis[i][j][k];
                    ansy=i;
                    ansm=j;
                    ansd=k;
                }
            }
        }
    }
    if(ansd<10) printf("0%d-",ansd);
    else printf("%d-",ansd);
    if(ansm<10) printf("0%d-",ansm);
    else printf("%d-",ansm);
    printf("201%d\n",ansy);
    return 0;
}
View Code

Problem C

题目大意:有n个箱子,每个箱子里有若干个小球(可以为0个),有一个操作,选取

一个箱子i(这个箱子里的小球不能为0),将里面的小球全部都拿出来,一次一个分给

i+1,i+2...,超过n则分给1,2,3...一直循环知道小球分完,现在给你分完之后各个箱子里的

小球个数,和最后一个小球分给了哪个箱子x,让你输出原来箱子里德小球数。

 

思路:刚开始我以为题目的意思是每个箱子里都至少有一个小球,那么起始位置肯定是

分完之后最少的那个,然后全部箱子里的小球减去最小值,从起始点开始模拟。wa了几次

因为箱子里的小球个数可能为0,可以有多个最小值,这样的话,我们可以将各个小球的

值减去都减去最小值(也就是分小球分过的完整轮数),然后从x从后往前模拟就可以了。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll a[100005],mn,n,m;
int main()
{
    mn=1e18;
    scanf("%I64d%I64d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d",&a[i]);
        mn=min(mn,a[i]);
    }
    for(int i=1;i<=n;i++)a[i]-=mn;
    ll sum=n*mn;
    while(a[m])
    {
        a[m]--;
        m--;sum++;
        if(m==0)m=n;
    }
    a[m]=sum;
    for(int i=1;i<=n;i++) printf("%I64d%c",a[i],n==i? '\n':' ');
    return 0;
}
View Code

Problem D

题目大意:有一棵树,每条边有一个权值,节点的权值等于连接它的各个边的权值的和,

每个点是黑色或者白色,相邻节点的颜色不能一样。现在只给你,节点的颜色和权值,

让你求各个边的情况。

 

思路:我们先将黑的节点都放一起,白节点也都放一起,然后从小到大排序,每次从

两堆中分别取出一个,定点权值小的那个肯定是端点,将这两个连边,边的权值为较小

的节点权值,较大节点继续留下和另一个不同颜色的点比较,一直这样构造下去。

我好菜啊,没写出来。。。

#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define P pair
using namespace std;
int n;
vector<P<int,int> > V[2];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int c,s;
        scanf("%d%d",&c,&s);
        V[c].pb(mp(s,i));
    }
    sort(V[0].begin(),V[0].end());
    sort(V[1].begin(),V[1].end());
    for(int i=0,j=0;i<V[0].size() && j<V[1].size();)
    {
        int mn=min(V[0][i].first,V[1][j].first);
        V[0][i].first-=mn;V[1][j].first-=mn;
        printf("%d %d %d\n",V[0][i].second,V[1][j].second,mn);
        if(V[0][i].first) j++;
        else if(V[1][j].first) i++;
        else if(i+1<V[0].size()) i++;
        else j++;
    }
    return 0;
}
View Code

 Problem E

题目大意:给你一堆点和9个数字(这九个数字的和为点的总数)让你用平行于x轴的两条线

和平行于y轴的两条线将这些点分为九分,使其与9个数字的任意一种排列一一对应,问你

有没有这样的一种分法,这题补了好久,我好菜。

题解:大体思路是先枚举九个数字的每一种排列,然后判断这种排列可不可行。在判断

每一种排列可不可行的时候,我们可以先判断三行三列的情况,然后再判断其他块中的

点的数量,这样我们就需要一个工具来快速地知道一个区域内有多少点,这样我们就能

想到用线段树,以x轴建树,每个节点存y的值,并将这个节点所对应区间的y的值排序。

详细看代码:

#include<bits/stdc++.h>
#define pii pair<int,int>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
using namespace std;
const int N=1e5+10;
pii p[N];//存点
vector<int> st[N<<2];//建树
int x[N],y[N],n,ax[3],ay[3],b[10],id[10],a[10];//x[N]所有点x的值,y[N]同理;
void build(int l,int r,int rt)
{
    for(int i=l;i<=r;i++) st[rt].push_back(p[i].se);
    sort(st[rt].begin(),st[rt].end());
    if(l==r) return;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
int query(int x,int y,int l,int r,int rt)
{
    if(p[l].fi>x) return 0;
    if(p[r].fi<=x)
    {
        return upper_bound(st[rt].begin(),st[rt].end(),y)-st[rt].begin();
    }
    int m=(l+r)>>1;
    return query(x,y,lson)+query(x,y,rson);
}
bool judge()
{
    int sx[3],sy[3];sx[0]=0,sy[0]=0;
    sx[1]=a[1]+a[4]+a[7];sx[2]=sx[1]+a[2]+a[5]+a[8];
    sy[1]=a[1]+a[2]+a[3];sy[2]=sy[1]+a[4]+a[5]+a[6];
    for(int i=1;i<=2;i++)
    {
        if(x[sx[i]]==x[sx[i]+1]) return false;//如果x[sx[i]]==x[sx[i]+1],因为这两个点相等,不能成功分开,这种排列错误;
        if(y[sy[i]]==y[sy[i]+1]) return false;//同上
    }
    int fx[3],fy[3];
    for(int i=1;i<=2;i++) fx[i]=x[sx[i]],fy[i]=y[sy[i]];
    if(query(fx[1],fy[1],1,n,1)!=a[1]) return false;//线段树快速询问;
    if(query(fx[1],fy[2],1,n,1)!=a[1]+a[4]) return false;
    if(query(fx[2],fy[1],1,n,1)!=a[1]+a[2]) return false;
    if(query(fx[2],fy[2],1,n,1)!=a[1]+a[2]+a[4]+a[5]) return false;
    for(int i=1;i<=2;i++) ax[i]=fx[i],ay[i]=fy[i];
    return true;
}
/*
a[1]  a[2]  a[3]

a[4]  a[5]  a[6]

a[7]  a[8]  a[9]
*/
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&p[i].fi,&p[i].se);
        x[i]=p[i].fi;y[i]=p[i].se;
    }
    sort(p+1,p+n+1);sort(x+1,x+1+n);sort(y+1,y+1+n);//排序
    for(int i=1;i<=9;i++) scanf("%d",&b[i]),id[i]=i;
    build(1,n,1);
    do
    {
        for(int i=1;i<=9;i++) a[i]=b[id[i]];
        if(judge())//判断这种排列可不可行
        {
            printf("%f %f\n",ax[1]+0.5,ax[2]+0.5);
            printf("%f %f\n",ay[1]+0.5,ay[2]+0.5);
            return 0;
        }
    }while(next_permutation(id+1,id+10));//枚举9个数字的排列情况
    puts("-1");
    return 0;
}
View Code

 

posted @ 2017-07-19 15:37  NotNight  阅读(201)  评论(0编辑  收藏  举报