A:判断一个数是否有大于1的奇因子。奇数直接yes,偶数判断一下是不是2的幂
while(t--) { ll n; cin >> n; if(n%2==0) { while(!(n&1)) { n/=2; } if(n == 1) cout << "NO" << endl; else cout << "YES" << endl; } else cout << "YES" << endl; }
B:判断一个数n能不能用2020和2021表示。分别记录n除以2020和mod2020的值,比较大小。
while(t--) { int n;cin >> n; int tmp=n/2020,temp=n%2020; if(temp<=tmp) cout << "YES" << endl; else cout <<"NO"<< endl; }
C:给出男生、女生的总个数 a,b 和配对的组数 k。其中(x,y) 为一对,x表示男生编号,y表示女生编号。询问找出 2 个组且其中的男生女生不重复的挑选方法数。
思路1:统计男女生每个编号出现的次数cnta,cntb,当我们选择一对后,剩下还能选择就是k-(cnta-1)-(cntb-1)-1,cnta-1代表除了当前这一对男生可与其它女生配对的数量,cntb-1同理,最后再减一是减去我们最开始选择的那一对,剩下差值就为我们还能选择的对数。
while(t--) { int aa,bb,k; cin >> aa >> bb >> k; memset(vis1,0,sizeof(vis1)); memset(vis2,0,sizeof(vis2)); for(int i=1;i<=k;i++) { cin >> a[i]; vis1[a[i]]++; } for(int i=1;i<=k;i++) { cin >> b[i]; vis2[b[i]]++; } ll ans=0; for(int i=1;i<=k;i++) { ll cnt1=vis1[a[i]]-1,cnt2=vis2[b[i]]-1; ans+=k-cnt1-cnt2-1; } cout << ans / 2 << endl; }
思路2:所有情况减去重复的情况。(long long)
while (T--) { cin >> a >> b >> k; for (int i = 0; i <= a; i++)A[i] = 0; for (int i = 0; i <= b; i++)B[i] = 0; for(int i = 1; i <= k; i++) { int x; cin >> x; A[x]++; } for(int i = 1; i <= k; i++) { int x; cin >> x; B[x]++; } ll ans = 1ll * k * (k - 1) / 2ll; for(int i = 1; i <= a; i++) { ans -= 1ll * A[i] * (A[i] - 1ll) / 2ll; } for(int i = 1; i <= b; i++) { ans -= 1ll * B[i] * (B[i] - 1ll) / 2ll; } cout << ans << endl; }
D:删除内存和至少为m的应用,问最少将失去多少方便点。方便点要么为1要么为2,将每个应用按照方便点分类再排序,方便点为2的应用(v2)按从小到大,方便点为1的应用(v1)按从大到小排序。贪心,先将v2中的内存和累加,再遍历一遍,每当内存和大于等于m更新一次ans的值,再每次舍弃v2中最小的,去取v1中最大的,因为这样操作能使内存和尽可能的大于或接近m,我们就可以尽可能的少删除应用从而使得失去的方便点尽可能少。
while(t--) { int n,m; cin >> n >> m; ll sum=0; for(int i=1;i<=n;i++) cin >> a[i],sum+=a[i]; for(int i=1;i<=n;i++) cin >> b[i]; if(sum<m) { cout << "-1" << endl; continue; } vector<int>v1,v2; for(int i=1;i<=n;i++) { if(b[i]==1) v1.push_back(a[i]); else v2.push_back(a[i]); } sort(v1.begin(),v1.end(),greater<int>());//方便点为1的按照内存从大到小排列 sort(v2.begin(),v2.end());//方便点为2的按照从小到大 ll s=0; for(auto i : v2) s+=i;//方便点为2的内存和 int tmp=0,ans=INF; for(int i=0;i<=v2.size();i++) { while(tmp<v1.size()&&s<m) s+=v1[tmp],tmp++;//tmp代表选择了多少个方便点为1的应用 if(s>=m) ans=min(ans,(int)(v2.size()-i)*2+tmp);//v2.size()-i代表此时选择了多少个方便点为2的应用 if(i<v2.size()) s-=v2[i]; } cout << ans << endl; }
E:有n个数,第i个数值为ai,取k个数,要求和最大,问最多有多少中情况。
思路:贪心,从大到小排序,选前k个,看最小值有几个,求组合数。因为数据很小,可以用杨辉三角也可以用lucas。我们在取的时候比较一下当前这个数有多少个与它相等的数,记为cnt,将cnt与k比较,如果cnt<=k,那么就只有一种情况,全选,然后更新k值,k=k-cnt,继续遍历。如果cnt>k,那就说明有多种取法,即组合数C(cnt,k)。下面附上杨辉三角解法。
int main() { cin >> t; comb[0][0] = 1; for (int i = 1; i <= 1010; i++) { comb[i][0] = 1; for (int j = 1; j <= i; j++) comb[i][j] = (comb[i - 1][j] + comb[i - 1][j - 1]) % MODNUM;//MODNUM=1000000007 } while(t--) { memset(rec, 0, sizeof(rec)); int n, k; cin >> n >> k; for (int j = 1; j <= n; j++) { int tmp; cin >> tmp; rec[tmp]++; } for (int j = n; j > 0; j--) if (rec[j] < k) k -= rec[j]; else { cout << comb[rec[j]][k] << endl; break; } } return 0; }