2018-2019 ACM-ICPC, NEERC, Southern Subregional Contest, Qualification Stage_组队训练
A. Coffee Break
题意:Monocarp得到一份工作,每天要工作 m 分钟,他有一个爱好,喜欢在休息的时候喝咖啡,但是他的老板不乐意了,就给他规定了个时间 d,在 d 分钟内只能喝一杯咖啡。现给出Monocarp喝 n 杯咖啡的时间点,问最少需要几天喝完?并输出每个时间点的咖啡在第几天喝。
题解:优先队列
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=2e6+10; struct node{ ll a; int id; }s[maxn]; bool cmp1(node x,node y) { return x.a<y.a; } ll ans[maxn]; typedef pair<ll,ll> pre; struct cmp{ bool operator ()(const pre p1,const pre p2){ return p1.second>p2.second; } }; ll num[maxn]; int main(){ priority_queue< pre,vector<pre>,cmp >q; ll n,m,d; cin>>n>>m>>d; for(int i=1;i<=n;i++){ scanf("%lld",&s[i].a); s[i].id=i; } sort(s+1,s+n+1,cmp1); q.push(make_pair(1,s[1].a)); ans[s[1].id]=1; int day=1; for(int i=2;i<=n;i++){ //cout<<q.top().first<<endl; if(q.top().second+d+1>s[i].a){ day++; q.push(make_pair(day,s[i].a)); ans[s[i].id]=day; }else{ int dd=q.top().first; q.pop(); ans[s[i].id]=dd; q.push(make_pair(dd,s[i].a)); } } printf("%d\n",day); for(int i=1;i<=n;i++){ printf("%lld%c",ans[i]," \n"[i==n]); } }
B. Glider:
题意:给n个区间和高度h,区间水平移动,非区间每一步就向下移动一步,起点任取,问最远到哪;
题解:二分+前缀和
#include<bits/stdc++.h> #define ll long long int using namespace std; const int maxn = 2e5+5; struct node { ll s,e; ll t; }x[maxn]; ll len[maxn]; ll pre[maxn]; ll plen[maxn]; int main() { ll n,m; cin>>n>>m; ll maxx = 0; for(int i=1;i<=n;i++) { cin>>x[i].s >>x[i].e; x[i].t = x[i].e - x[i].s ; } int count = 0; for(int i=2;i<=n;i++) { len[i] = x[i].s - x[i-1].e; } for(int i=2;i<=n;i++) { plen[i] = plen[i-1] + len[i]; } for(int i=1;i<=n;i++) { pre[i] = pre[i-1] + x[i].e - x[i].s; } for(int i=1;i<=n;i++) { ll te = x[i].e + 1; ll found = m - 1; int left = 1,right = i; int maxxx = 0; while(left <= right) { int mid = (left + right)>>1; ll tt = plen[i] - plen[i-mid+1]; if(tt<=found) { maxxx = max(maxxx ,mid); left = mid + 1; } else { right = mid - 1; } } ll Maxx = found + pre[i] - pre[i - maxxx] + 1; maxx = max(maxx ,Maxx); // cout<<i<<" "<<Maxx<<" "<<maxxx<<endl; } cout<<maxx<<endl; }
C. Bacteria
题意:给N个数,只有相同的两个数才能结合起来,加在一起。比如说2只有和2结合,成为4。
思路:最后合成的一定是2的幂次的倍数,先判断每个数是不是2的幂次的倍数,然后找最小的2的幂次大于他们的和就是那个数了。直接模拟
#include<bits/stdc++.h> /*#include<cstring> #include<set> #include<map> #include<iostream> #include<algorithm> #if(__cplusplus == 201103L) #include <unordered_map> #include <unordered_set> #else #include <tr1/unordered_map> #include <tr1/unordered_set> namespace std { using std::tr1::unordered_map; using std::tr1::unordered_set; } #endif*/ #define ll long long #define mem(a,b) memset(a,b,sizeof a) #define pb push_back #define de(x) cout<<x<<endl #define dd(x) cout<<x<<" " #define is insert using namespace std; const int maxn =10001000; const int mod = 1e9+7; typedef pair<ll, ll> p1; typedef pair< ll, pair<ll,ll > >p2; inline int rd(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} void out(int a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');} const int INF = 0x3f3f3f3f; int MOVE[4][2]={ {0,1}, {1,0}, {0,-1}, {-1,0}, }; ll ok(ll x){ ll y=1; while(1){ //cout<<y<<endl; if(x>=y){ y*=2; } else{ break; } } return y/2; } ll a[200005]; void run() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; } sort(a+1,a+1+n); int pp = a[1]; for(int i=1;i<=n;i++) { int xx = a[i]/pp; if(a[i]%a[1]!=0) { puts("-1"); return; } while(xx%2==0) { xx/=2; } //cout<<xx<<endl; if(xx!=1) { puts("-1"); return; } a[i] = a[i]/pp; } ll sum = 0; for(int i=1;i<=n;i++) { sum+=a[i]; } ll xx = 1; while(xx<sum) { xx*=2; } ll ans = xx - sum; // cout<<ans<<endl; ll yy=xx/2; ll num=0; while(ans>1){ //cout<<ok(ans)<<endl; ans-=ok(ans); //cout<<ans<<endl; num++; } // cout<<num<<endl; if(ans==1) num++; cout<<num<<endl; } signed main() { //std::ios::sync_with_stdio(false); run(); }
D. Masquerade strikes back
题意:给出n个数,看是否能由不同的有序队相乘得来。
题解:直接模拟,暴力求解,然后用vector优化。
#include<bits/stdc++.h> /*#include<cstring> #include<set> #include<map> #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #if(__cplusplus == 201103L) #include <unordered_map> #include <unordered_set> #else #include <tr1/unordered_map> #include <tr1/unordered_set> namespace std { using std::tr1::unordered_map; using std::tr1::unordered_set; } #endif*/ #define ll long long #define mem(a,b) memset(a,b,sizeof a) #define pb push_back #define de(x) cout<<x<<endl #define dd(x) cout<<x<<" " #define is insert using namespace std; const int maxn =2001000; const int mod = 1e9+7; typedef pair<ll, ll> p1; typedef pair< ll, pair<ll,ll > >p2; inline int rd(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} void out(int a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');} const int INF = 0x3f3f3f3f; int MOVE[4][2]={ {0,1}, {1,0}, {0,-1}, {-1,0}, }; int a[maxn]; int b[maxn],c[maxn]; vector<int>v[200005]; vector<int>::iterator it; int mm[10000005]; void run() { int n ; scanf("%d",&n); int qq = 1; for(int i=1;i<=n;i++) { scanf("%d",&a[i]); if(!mm[a[i]]) { mm[a[i]] = qq; qq++; for(int j=1;j*j<=a[i];j++) { if(a[i]%j==0) { if(j!=a[i]/j) { v[qq-1].pb(j); v[qq-1].pb(a[i]/j); } else{ v[qq-1].pb(j); } } } b[i] = 1,c[i] = a[i]; v[qq-1].erase(v[qq-1].begin()); } else{ int pp = mm[a[i]]; if(v[pp].size() == 0) { printf("NO"); return; } it = v[pp].begin(); b[i] = *it,c[i] = a[i]/(*it); v[pp].erase(v[pp].begin()); } } printf("YES\n"); for(int i=1;i<=n;i++) { out(b[i]),printf(" "),out(c[i]),printf("\n"); } } signed main() { //std::ios::sync_with_stdio(false); run(); }
E. Painting the Fence
题意:给n个初始颜色,m次涂色,每指定一种颜色这种颜色最左到最右染色,问最后的颜色序列
题解:模拟然后用set来优化,set来存所在数的下标就行
#include<bits/stdc++.h> #define ll long long int #define mem(a,b) memset(a,b,sizeof a) using namespace std; const int maxn = 300010; int a[maxn]; set<int>s[maxn]; set<int>::iterator it; set<int>::reverse_iterator rit; int vis[maxn]; int ans[maxn]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) { cin>>a[i]; s[a[i]].insert(i); } int m; cin>>m; while(m--) { int x; cin>>x; if(vis[x]||s[x].size()<2) { continue; } it = s[x].begin(); rit = s[x].rbegin(); int l = *it + 1; int r = *rit - 1; for(int j = l;j <= r;j ++) { s[a[j]].erase(j); if(vis[a[j]]&&s[a[j]].size()>0) { it = s[a[j]].begin(); j = *it; s[a[j]].erase(j); } } vis[x] = 1; } int count = 0; for(int i=1;i<=n;i++) { if(s[a[i]].size()>1&&vis[a[i]]) { it = s[a[i]].begin(); rit = s[a[i]].rbegin(); for(int j = *it ;j <= *rit ;j ++) { ans[j] = a[i]; } i = *rit; } else{ ans[i] = a[i]; } } for(int i=1;i<=n;i++) { cout<<ans[i]<<" "; } }
F. Tickets
前缀和
#include<bits/stdc++.h> /*#include<cstring> #include<set> #include<map> #include<iostream> #include<algorithm> #if(__cplusplus == 201103L) #include <unordered_map> #include <unordered_set> #else #include <tr1/unordered_map> #include <tr1/unordered_set> namespace std { using std::tr1::unordered_map; using std::tr1::unordered_set; } #endif*/ #define ll long long #define mem(a,b) memset(a,b,sizeof a) #define pb push_back #define de(x) cout<<x<<endl #define dd(x) cout<<x<<" " #define is insert using namespace std; const int maxn =10001000; const int mod = 1e9+7; typedef pair<ll, ll> p1; typedef pair< ll, pair<ll,ll > >p2; inline int rd(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} void out(int a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');} const int INF = 0x3f3f3f3f; int MOVE[4][2]={ {0,1}, {1,0}, {0,-1}, {-1,0}, }; int sum(int num) { int x1=0,x2=0,pos=1; while(num>0){ int x=num%10; num/=10; if(pos<=3){ x1+=x; }else{ x2+=x; } pos++; } return abs(x2-x1); } int a[maxn]; int p[maxn]; void init() { for(int i=0;i<=999999;i++){ for(int j=0;j<sum(i);j++){ p[i]+=a[j]; } a[sum(i)]++; } } void run() { init(); int num; int t = rd(); while(t--) { scanf("%d",&num); printf("%d\n",p[num]); } } signed main() { //std::ios::sync_with_stdio(false); run(); }
G Tree Reconstruction
题意:n个点,给出n-1条边 每条边的左右部分的 最大节点编号 是否能还原这个树
题解:首先给出的两点一定要有一个是节点n,否则一定不符合然后我们保存一下较小的那个节点,排序,从小到大开始连接,若遇见一样的,那就看是否有更小的节点没有连接,这样我们构造一个一条线的树就可以了
#include<bits/stdc++.h> #define ll long long int using namespace std; int minn[1010]; int tree[1010]; set<int>s; set<int>::iterator it; int main() { int n; cin>>n; int ans = 0; for(int i=1;i<=n-1;i++) { int x,y; cin>>x>>y; if(max(x,y) == n) ans++; minn[i] = min(x,y); s.insert(i); //cout<<i<<endl; } if(ans!=n-1) { puts("NO"); return 0; } sort(minn+1,minn+n); s.insert(n); tree[1] = minn[1]; s.erase(minn[1]); for(int i=2;i<=n-1;i++) { it = s.begin(); //cout<<*it<<endl; if(minn[i] == minn[i-1]) { if(*it > minn[i]) { puts("NO"); return 0; } else{ //cout<<*it<<endl; tree[i] = *it; s.erase(*it); } } else{ tree[i] = minn[i]; s.erase(minn[i]); } } tree[n] = n; puts("YES"); for(int i=2;i<=n;i++) { printf("%d %d\n",tree[i-1],tree[i]); } }
H. Theater Square
简单数学
#include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=2e6+10; int main() { int n,m,sum=0; int x1,y1,x2,y2; cin>>n>>m; cin>>x1>>y1>>x2>>y2; int d=(x2-x1+1); if(y1%2==0)sum+=d; if((m-y2)%2==1)sum+=d; if(m%2==1){ sum+=(n-d); } printf("%d\n",sum/2+(sum%2)); }
I. Heist
签到题
#include<bits/stdc++.h> using namespace std; const int maxn=1e3+10; int a[maxn]; int main(){ int n; scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&a[i]); sort(a,a+n); int maxx,minx; maxx=a[n-1]; minx=a[0]; printf("%d\n",a[n-1]-a[0]+1-n); }
J Buying a TV Set
签到题:
#include<bits/stdc++.h> /*#include<cstring> #include<set> #include<map> #include<iostream> #include<algorithm> #if(__cplusplus == 201103L) #include <unordered_map> #include <unordered_set> #else #include <tr1/unordered_map> #include <tr1/unordered_set> namespace std { using std::tr1::unordered_map; using std::tr1::unordered_set; } #endif*/ #define ll long long #define mem(a,b) memset(a,b,sizeof a) #define pb push_back #define de(x) cout<<x<<endl #define dd(x) cout<<x<<" " #define is insert using namespace std; const int maxn =10001000; const int mod = 1e9+7; typedef pair<ll, ll> p1; typedef pair< ll, pair<ll,ll > >p2; inline int rd(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;} void out(int a) {if(a<0)putchar('-'),a=-a;if(a>=10)out(a/10);putchar(a%10+'0');} const int INF = 0x3f3f3f3f; int MOVE[4][2]={ {0,1}, {1,0}, {0,-1}, {-1,0}, }; void run() { ll a,b,x,y; cin>>a>>b>>x>>y; ll ans = __gcd(x,y); ll xx = x/ans; ll yy = y/ans; ll maxx1 = a/xx,maxx2 = b/yy; if(min(maxx1,maxx2) == 0) { puts("0"); return; } ll left = 0,right = min(maxx1,maxx2); ll maxx = 0; while(left <= right) { ll mid = (left + right)>>1; if(xx*mid<=a&&yy*mid<=b) { left = mid + 1; maxx = max(maxx,mid); } else { right = mid - 1; } } cout<<maxx<<endl; } signed main() { //std::ios::sync_with_stdio(false); run(); }
(K) Medians and Partition
思维题:
#include<bits/stdc++.h> using namespace std; int main(){ int n,m,k; scanf("%d%d ",&n,&m); int a=0,b=0; while(n--){ scanf("%d",&k); if(k>=m) a++; else b++; } printf("%d\n",max(a-b,0)); }
L. Ray in the tube
待补

浙公网安备 33010602011771号