2018 JUST Programming Contest 1.0

Time:2018.4.21  8:40-11:40

Link

Tutorial


A

题意

 

分析

 


B          solved by ym

题意

问平均数为a的n个数,最多有几个数不同

分析

ym:czh赛时清醒的发现可以尽量多的选,而不是直接是一个定值,总和n×a,尽可能多的选那么我们应该怎么选:显然我们想要更多不同的数字,那么我们一定是选择尽可能多的小的           数字,因为用一个大的数字代替几个小的数字会减少小的数的数量,故二分最多可以用多少个小的数,剩下的数用小的数“稀释”,check方法:n-mid>=(n×a-(mid+1)*mid/2)

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn = 2e5+7;

long long n,a;

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&a);
        ll l=1,r=n,mid;
        while(l<r)
        {
            mid=(l+r+1)>>1;
            if((n*a-mid*(mid+1)/2)>=n-mid)
                l=mid;
            else
                r=mid-1;
        }
        printf("%lld\n",l);
    }
    return 0;
}

C             solved by  ym &czh

题意

问题可以转化为:给一个n,求小于n且与其互质的数(T<=1e5,n<=1e6)

分析)

ym:背锅,想到欧拉函数,但以为是质数= =,欧拉函数:对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1 ),显然一个欧拉函数就解决了


D      solved by ym

题意

给一个无向图n个点m条边,每条边有一个权值w, 给出K个重要的点,问一个包含全部重要的点的子图的最小值 k (2 ≤ n ≤ 15) () (1 ≤ k ≤ n),

分析

ym:由于n很小,考虑状压dp,知道哪些点已经选,将没有选的点逐渐的添加到已选集合,dp[mask]:从mask状态下出发的最小值

时间复杂度:由于每个点有2^n种状态,O(n*2^n)

#include<bits/stdc++.h>
#define sc scanf
#define pr printf
#define ll long long
using namespace std;

const int maxn = 15+7;

int tot,head[maxn*maxn*2],to[maxn*maxn*2],nxt[maxn*maxn*2],w[maxn*maxn*2];
int t,u,v,c,n,m,k;
int Mask,ans,dp[(1<<16)+7];

void init()
{
    Mask=0;
    tot=0;
    memset(head,0,sizeof(head));
    memset(w,0,sizeof(nxt));
    memset(nxt,0,sizeof(nxt));
}

void add(int u,int v,int c){
    to[++tot]=v;
    w[tot]=c;
    nxt[tot]=head[u];
    head[u]=tot;
}

int maskdp(int x)
{
    if(dp[x]!=-1)  return dp[x];
    if((x&Mask)==Mask) return 0;
    dp[x]=1e9;
    for(int i=0;i<n;i++)
    {
        if(((x>>i)&1))
        {
            for(int j=head[i];j;j=nxt[j])
            {
                int v=to[j];
                if(!((x>>v)&1))
                dp[x]=min(dp[x],w[j]+maskdp(x|(1<<v)));
            }
        }
    }
    return dp[x];
}

int main()
{
    sc("%d", &t);
    while(t--){
        init();
        sc("%d%d%d",&n,&m,&k);
        for(int i=1;i<=m;i++){
            sc("%d%d%d", &u,&v,&c);
            u--,v--;
            add(u,v,c),add(v,u,c);
        }
        int x;
        for(int i=1;i<=k;i++){
            sc("%d",&x);
            x--;
            Mask|=(1<<x);
        }
        int answer=1e9;
        memset(dp,-1,sizeof(dp));
        for(int i=0;i<n;i++)
        {
            answer=min(answer,maskdp(1<<i));
        }
        pr("%d\n",answer);
    }
    return 0;
}

E       solved by ym

签到


F           solved  by ym

题意

给出一个n×m的网格,每个格子有一数字num,现有q条询问,每个询问给出询问的网格范围(a<=x<c ,b<=y<=d),问这些网格的median值(median:(2,1,3)==2,(4,2,3,1)==2)

(T<=100,1<=n,m<=100,1<=q<=1e5,1<=num<=500,sum of  n×m <= 3×1e5,sum of  q<=1e6)

分析

由于num<=500,考虑用二维前缀和记录每个数字出现的频率,对于每次询问,median即为从小到大出现在出现median位置即可

时间复杂度O(T*n*m*num)

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int sum[105][105][505];
int a[105][105];
int now[505];
int t,n,m,q;

int main()
{
    scanf("%d",&t);
    while(t--){
            memset(sum,0,sizeof(sum));
        scanf("%d%d%d", &n,&m,&q);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                scanf("%d",&a[i][j]);
            }
        }
     //   cout<<123<<endl;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                int na=a[i][j];
                sum[i][j][na]++;
                for(int k=1;k<=500;k++)
                {
                    if(i==1){
                        if(j!=1){
                            sum[i][j][k]+=sum[i][j-1][k];
                        }
                    }
                    else {
                        if(j==1){
                            sum[i][j][k]+=sum[i-1][j][k];
                        }
                        else{
                            sum[i][j][k]=sum[i][j][k]+sum[i][j-1][k]+sum[i-1][j][k]-sum[i-1][j-1][k];
                        }
                    }
                }
            }
        }
        //cout<<113<<endl;
        int x,y,xx,yy;
        while(q--)
        {
            memset(now,0,sizeof(now));
            scanf("%d%d%d%d",&x,&y,&xx,&yy);
            int allsum=(xx-x+1)*(yy-y+1);
            allsum=(allsum+1)/2;
            for(int i=1;i<=500;i++)
            {
                int ans=sum[xx][yy][i]-sum[xx][y-1][i]-sum[x-1][yy][i]+sum[x-1][y-1][i];
                allsum-=ans;
                if(allsum<=0)
                {
                    printf("%d\n",i);
                    break;
                }
            }
        }
    }
    return 0;
}

G

题意

几何

分析

 czh来解决一下?


H    solve by czh&ym

题意

给出一个字符串  下面给出n次替换,问有多少次替换执行完后,这个字符串成为一个回文串

分析

czh:首先统计有多少个左右不同的字符对,每次更改后,检查更改点字符对的变换,每次执行后如果不同的字符对为0则ans++。我的最大问题在于中点无论怎么变,num都不会改变。需要特判。


I      

签到 


J     solved by  ym

题意

给一个区间[L,R],现给出一种切割,一个数可以从中间分成两半(1001???),这个数不含0并且前一半和后一半互质,问区间满足这种切割的最大值 

分析

ym:质数间隙了解一下?(暂且可以认为为320),暴力check


K      solved by  ym

题意

给出ACM比赛的规则,问最后各个奖的归属

分析

ym:所以说写模拟题会送命

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=37;
const int maxm=10000+7;

struct node
{
    int p,d,r,o;
    friend bool operator < (node a,node b){
        return a.o<b.o;
    }
}t[maxm];

int tt,n,m,k;
bool v[maxn][maxn];///是否访问过
int f[maxn][maxn]; /// 每个人每个题在答对之间错的次数
int num[maxn]; ///每个队的一血数量
int fb[maxn];
int ans[maxn];
string s;

int hs()
{
    int sum=0;
    sum=s[0]*100+s[1]*10+s[2]*1;
    sum*=60;
    sum+=s[4]*10+s[5];
    return sum;
}

int main()
{
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d%d%d", &n, &m,&k);
        memset(f,0,sizeof(f));
        memset(v,false,sizeof(v));
        memset(num,0,sizeof(num));
        for(int i=1;i<=k;i++)
        {
            scanf("%d%d%d",&t[i].p,&t[i].d, &t[i].r);
            cin>>s;
            t[i].o=hs();
        }
        for(int i=1;i<=n;i++) fb[i]=-1;
        for(int i=1;i<=m;i++) ans[i]=-1;
        sort(t+1,t+k+1);
        int st=-1,ed=-1,maxdd=0,maxf=0;
        for(int i=1;i<=k;i++)
        {
            int pp=t[i].p, dd=t[i].d, rr=t[i].r;
            if(rr==1){
                ed=dd;
                if(st==-1)  st=dd;
                if(fb[pp]==-1) fb[pp]=dd;
                if(!v[dd][pp])
                {
                    num[dd]++;
                    maxdd=max(maxdd,num[dd]);
                }
                ans[dd]=max(ans[dd],f[dd][pp]);
            }
            else
                f[dd][pp]++;
            v[dd][pp]=1;
        }
        for(int i=1;i<=n;i++)
            printf("%d%c",fb[i],i==n?'\n':' ');
        printf("%d %d ",st,ed);
        for(int i=1;i<=m;i++)
            if(num[i]==maxdd)
            {
                printf("%d ",i);break;
            }
        bool flag=true;
        maxf=-5;
        for(int j=1;j<=m;j++)
        {
            maxf=max(maxf,ans[j]);
        }
        for(int j=1;j<=m;j++)
        {
           if(ans[j]==maxf)
           {
               cout<<j<<endl;
               break;
           }
        }
    }
    return 0;
}

Summary

Ym:菜菜啊,K题过的人好多,大家都会大模拟呀,这个水平去reginoal药丸,大力切题呀

Czh:

posted @ 2018-04-21 11:41  Deadlined  阅读(287)  评论(0编辑  收藏  举报