2019 Multi-University Training Contest 7
1001 A + B = C
题目链接
题意:给出a,b,c,寻找x,y,z满足式子。
思路:将a,b,c三个数补位后继0至长度相同,可能满足情况为
- b数字移位 和 c-a的数字移位比较
- a数字移位 和 c-b的数字移位比较
- b数字移位 和 10*c-a的数字移位比较
- a数字移位 和 10*b-a的数字移位比较
模拟一个大数减法,四次比较
#include <bits/stdc++.h> #define maxn 100005 using namespace std; char a[maxn],b[maxn],c[maxn]; int numa[maxn],numb[maxn],numc[maxn]; int ans1,ans2,ans3; void sub(char s1[],char s2[],int n,int m) { int i,j; for(i=0; i<n; i++) numa[i]=s1[n-i-1]-'0'; for(i=0; i<m; i++) numb[i]=s2[m-i-1]-'0'; for(i=0; i<n; i++) numc[i]=numa[i]-numb[i]; for(i=0;i<n;i++){ if(numc[i]<0) { while(numc[i]<0) { numc[i+1]=numc[i+1]-1; numc[i]+=10; } } } } bool isbig(char s1[],char s2[],int n,int m) { if(n>m) return 1; else if(n==m){ int k=strcmp(s1,s2); if(k>0) return 1; } return 0; } void input(){ scanf("%s%s%s",a,b,c); int lena=strlen(a); int lenb=strlen(b); int lenc=strlen(c); int len=max(lena,max(lenb,lenc)); ans1=ans2=ans3=0; int tlen=strlen(a); while(len>tlen) { a[tlen]='0'; a[++tlen]='\0'; ans1++; } tlen=strlen(b); while(len>tlen) { b[tlen]='0'; b[++tlen]='\0'; ans2++; } tlen=strlen(c); while(len>tlen) { c[tlen]='0'; c[++tlen]='\0'; ans3++; } } void solve(){ int lena=strlen(a); int lenb=strlen(b); int lenc=strlen(c); int i; if(isbig(c,a,lenc,lena)){ sub(c,a,lenc,lena); int flag=0; int Flag=1; int cnt=0; for(i=lenc-1;i>=0;i--){ if(!numc[i]) { if(!flag) continue; else { if(numc[i]!=b[cnt]-'0') Flag=0; cnt++; } }else{ flag=1; if(numc[i]!=b[cnt]-'0') Flag=0; cnt++; } if(!Flag)break; } for(i=cnt+1;i<lenb;i++) if(b[i]-'0'!=0) Flag=0; if(Flag){ ans2-=lenc-cnt; if(ans2<0) { ans1-=ans2; ans3-=ans2; ans2=0; } printf("%d %d %d\n",ans1,ans2,ans3); return ; } } if(isbig(c,b,lenc,lenb)){ sub(c,b,lenc,lenb); int flag=0; int Flag=1; int cnt=0; for(i=lenc-1;i>=0;i--){ if(!numc[i]) { if(!flag) continue; else { if(numc[i]!=a[cnt]-'0') Flag=0; cnt++; } }else{ flag=1; if(numc[i]!=a[cnt]-'0') Flag=0; cnt++; } if(!Flag)break; } for(i=cnt+1;i<lena;i++) if(a[i]-'0'!=0) Flag=0; if(Flag){ ans1-=lenc-cnt; if(ans1<0) { ans2-=ans1; ans3-=ans1; ans1=0; } printf("%d %d %d\n",ans1,ans2,ans3); return ; } } // cout<<"!"; c[lenc]='0'; c[++lenc]='\0'; ans3++; if(isbig(c,a,lenc,lena)){ sub(c,a,lenc,lena); int flag=0; int Flag=1; int cnt=0; for(i=lenc-1;i>=0;i--){ if(!numc[i]) { if(!flag) continue; else { if(numc[i]!=b[cnt]-'0') Flag=0; cnt++; } }else{ flag=1; if(numc[i]!=b[cnt]-'0') Flag=0; cnt++; } if(!Flag)break; } for(i=cnt+1;i<lenb;i++) if(b[i]-'0'!=0) Flag=0; if(Flag){ ans2-=lenc-1-cnt; if(ans2<0) { ans1-=ans2; ans3-=ans2; ans2=0; } printf("%d %d %d\n",ans1,ans2,ans3); return ; } } if(isbig(c,b,lenc,lenb)){ sub(c,b,lenc,lenb); int flag=0; int Flag=1; int cnt=0; for(i=lenc-1;i>=0;i--){ if(!numc[i]) { if(!flag) continue; else { if(numc[i]!=a[cnt]-'0') Flag=0; cnt++; } }else{ flag=1; if(numc[i]!=a[cnt]-'0') Flag=0; cnt++; } if(!Flag)break; } for(i=cnt+1;i<lena;i++) if(a[i]-'0'!=0) Flag=0; if(Flag){ ans1-=lenc-1-cnt; if(ans1<0) { ans2-=ans1; ans3-=ans1; ans1=0; } printf("%d %d %d\n",ans1,ans2,ans3); return ; } } printf("-1\n"); return; } int main(){ int t; scanf("%d",&t); while(t--){ input(); solve(); } }
1006 Final Exam
题目链接
题意:有n门课,课程总分是m,复习一门课程的时间为其分数x+1,要求保证有k门课程通过。求所需要的最少时间。
思路:考虑最糟糕情况,即最后n-k+1门课程平分了所有的m分数。对于前k-1门,我并不知道课程的具体顺序,所以每一门复习所需要的时间都是,对于后面总共n-k+1所需要的时间总和即为m+1。
#include <cstdio> #include <cmath> #include <iostream> typedef long long ll; using namespace std; int n,m,k; void input(){ scanf("%d%d%d",&n,&m,&k); } void solve(){ printf("%lld\n",(ll)ceil(1.0*(m+1)/(n-k+1))*(k-1)+m+1); } int main(){ int t; scanf("%d",&t); while(t--){ input(); solve(); } }
1010 Just Repeat
题目链接
题意:两个人玩游戏,第一人有n张牌,第二个人有m张,每张牌有其花色用数字表示,当其中一人选择了某种花色的牌,另一人就不能选择此花色的牌。谁不能拿谁输,求最后胜者。
思路:贪心考虑,优先的牌一定是出现次数最多的。在我方出现多,代表能选择更多次,在对方出现多代表能封对方更多牌。将双方都出现过的牌进行统计次数,从大到小排序,双方轮流贪心选择。
最后记录每个人的牌数,即只出现在自己方的牌+被自己选择的出现在双方的牌在自己手上出现次数。比较大小,若前者大于后者则胜利,否则失败。
据题解说卡了map,通过排序后类似多项式合并的方式优化。
#include <bits/stdc++.h> #define maxn 10000005 typedef unsigned long long ull; using namespace std; unsigned long long k1, k2; ull a[maxn],b[maxn]; pair<ull,ull> res[maxn]; bool cmp(pair<ull,ull> p,pair<ull,ull> q){ return p.first + p.second > q.first + q.second; } struct node{ ull val; ull cnt; }; node na[maxn],nb[maxn]; int n,m,p; unsigned long long rng() { unsigned long long k3 = k1, k4 = k2; k1 = k4; k3 ^= k3 << 23; k2 = k3 ^ k4 ^ (k3 >> 17) ^ (k4 >> 26); return k2 + k4; } void input(){ int i; scanf("%d%d%d",&n,&m,&p); if(p==1){ for(i=0;i<n;i++) scanf("%lld",&a[i]); for(i=0;i<m;i++) scanf("%lld",&b[i]); }else{ ull mod; scanf("%lld%lld%lld",&k1,&k2,&mod); for (i = 0; i < n; ++i) a[i] = rng() % mod; scanf("%lld%lld%lld",&k1,&k2,&mod); for (i = 0; i < m; ++i) b[i] = rng() % mod; } /* for(i=0;i<n;i++) cout<<a[i]<<" "; cout<<endl; for(int j=0;j<m;j++) cout<<b[j]<<" "; cout<<endl; */ } void solve(){ int i,j; sort(a,a+n); ull temp=a[0]; int cnt=1; int cnta=0; for(i=1;i<n;i++){ if(a[i]!=a[i-1]){ na[cnta].val=temp; na[cnta].cnt=cnt; cnt=1; temp=a[i]; cnta++; }else cnt++; } na[cnta].val=temp; na[cnta].cnt=cnt; cnta++; sort(b,b+m); temp=b[0]; cnt=1; int cntb=0; for(i=1;i<m;i++){ if(b[i]!=b[i-1]){ nb[cntb].val=temp; nb[cntb].cnt=cnt; cnt=1; temp=b[i]; cntb++; }else cnt++; } nb[cntb].val=temp; nb[cntb].cnt=cnt; cntb++; cnt=0; ull a=0,b=0; for(i=0,j=0;i<cnta&&j<cntb;) { // cout<<i<<' '<<cnta<<' '<<na[i].val<<' '<<na[i].cnt<<endl; // cout<<j<<' '<<cntb<<' '<<nb[j].val<<' '<<nb[j].cnt<<endl; // cout<<endl; if(na[i].val>nb[j].val){ b+=nb[j].cnt; j++; }else if(na[i].val<nb[j].val){ a+=na[i].cnt; i++; }else{ res[cnt++]=make_pair(na[i].cnt,nb[j].cnt); i++;j++; } } while(i<cnta){ a+=na[i].cnt; i++; } while(j<cntb){ b+=nb[j].cnt; j++; } sort(res,res+cnt,cmp); for(i=0;i<cnt;i++) { if(i%2==0) a+=res[i].first; else b+=res[i].second; } // cout<<a<<" "<<b<<endl; if(a>b) printf("Cuber QQ\n"); else printf("Quber CC\n"); } int main(){ int t; scanf("%d",&t); while(t--){ input(); solve(); } }
1011 Kejin Player
题目链接
题意:给出n行输入,第i行表示从第i级升级到第i+1级别需要花费ai费用。对于升级有pi的概率表示可以成功,对于1-pi的概率失败会导致等级返回至xi级。q个询问,求从第a级到第b级需要多少费用期望。
思路:期望dp,设dp[i]为升级到第i级别所需要的费用,其等级为xi=i时
否则,可推出公式
可以通过前缀和维护
#include <bits/stdc++.h> #define maxn 500005 typedef long long ll; using namespace std; const ll mod = 1000000007; int n, q; ll predif; ll dif[maxn];//dp[i+1]-dp[i] ll presum[maxn]; ll power_mod(ll a, ll b, ll m) { ll ans = 1; a %= m; while (b) { if (b & 1)ans = (ans*a) % m; a = (a*a) % m; b >>= 1; } return ans; }//power_mod(b,m-2,m) void input() { scanf("%d%d", &n, &q); int i; ll ri, si, xi, ai; presum[0] = 0; for (i = 1; i <= n; i++) { scanf("%lld%lld%lld%lld", &ri, &si, &xi, &ai); ll pi = ri * power_mod(si, mod - 2, mod) % mod; ll fpi = power_mod(pi, mod - 2, mod) % mod; if (xi == i) { dif[i] = -1ll * ai%mod; dif[i] = ((dif[i] * fpi )%mod-mod)%mod; } else { dif[i] = (((1 - pi) % mod*(presum[i - 1] - presum[xi-1]) % mod - ai) % mod ) % mod; dif[i] = ((dif[i] * fpi )%mod-mod)%mod; } presum[i] = ((presum[i - 1] + dif[i]) % mod - mod) % mod; } } void solve() { int i; int u, v; // for(i=1;i<=n;i++) // cout<<i<<' '<<dif[i]<<endl; for (i = 1; i <= q; i++) { scanf("%d%d", &u, &v); printf("%lld\n", -1ll * (((presum[v - 1] - presum[u - 1]) % mod-mod)%mod)); } } int main() { int t; scanf("%d", &t); while (t--) { input(); solve(); } }