2018 JUST Programming Contest 1.0
Time:2018.4.21 8:40-11:40
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: