Codeforces Round #697 (Div. 3)
阿新 • • 發佈:2021-01-27
技術標籤:codeforces演算法
目錄
A. Odd Divisor
標籤:數學
- 題設:T個樣例下,每個樣例只輸入一值n (2≤n≤1014),問:n是否存在一個大於1且為奇數的因子,存在輸出yes,否則輸出no。
- 思路:n為大於1的奇數直接符合要求,n為偶數的情況:暴力while迴圈除以2,到奇數或1為止,若此時n為1輸出no,反之yes。
- 程式碼:
#include<bits/stdc++.h>
#define ll long long
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int maxn= 2e5+5;
void solve()
{
ll n;cin>>n;
while (n%2==0) n/=2;
if(n==1) cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
int main()
{
IOS;
int t;cin>>t;
while(t--){ solve(); }
return 0;
}
B. New Year’s Number
標籤:數學
- 題設:T個樣例下,每個樣例只輸入一個值n(1≤n≤106) 。判斷值n是否能由任意數量的2020和2021混合相加構成。
- 思路:n減去最大數量的2020後,判斷剩餘的數,必須小於等於減去的2020個數。
- 程式碼:
#include<bits/stdc++.h>
#define ll long long
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int maxn= 2e5+5;
void solve()
{
int n;cin>>n;
int cnt=n/2020;
n -= cnt*2020;
if(n<=cnt) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
int main()
{
IOS;
int t;cin>>t;
while(t--){ solve(); }
return 0;
}
C. Ball in Berland
標籤:數學 計數 暴力
- 題設:T個樣例,每個樣例下,第一行輸入三個數,分別為代表男生總人數的n,女生總人數的m,和能配對成舞伴組合的總數量k。接下來兩行分別輸入構成k對組合的所有男生a1—ak,女生b1—bk(上下兩行,男女對應)。現在只能挑選兩對舞伴組合,且挑選的4個人必須互不相同,求在給定的資訊下所有可挑選的方案數。
- 思路:
4個人必須互不相同,且k對組合不會重複,
那麼,對所有出現的男生和女生按編號計數後,
迴圈遍歷,在考慮挑選出來的兩組順序的情況下,每對組合能和另一隊一起構成符合條件方案的個數為:
(na【i】為編號為i的男生出現在組合中的次數,nb【i】為編號為i的女生出現在組合中的次數。但因題目對挑選的兩隊組合不考慮順序,最後答案除以二。)
(k-1) - max(0,na【a【i】】-1) - max(0,nb【b【i】】-1)
- 程式碼:
#include<bits/stdc++.h>
#define ll long long
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int maxn= 2e5+5;
int na[maxn],nb[maxn];
int a[maxn],b[maxn];
void solve()
{
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n;i++) na[i]=0;
for(int i=1;i<=m;i++) nb[i]=0;
for(int i=1;i<=k;i++) cin>>a[i], na[a[i]]++;
for(int i=1;i<=k;i++) cin>>b[i], nb[b[i]]++;
ll ans=0;
for(int i=1;i<=k;i++)
{
ans += k-1;
ans -= max(0,na[a[i]]-1);
ans -= max(0,nb[b[i]]-1);
}
cout<<ans/2<<endl;
}
int main()
{
IOS;
int t;cin>>t;
while(t--){ solve(); }
return 0;
}
D. Cleaning the Phone
標籤:排序 字首和 二分查詢
- 題設:T個樣例下,每個樣例第一行輸入n和m,分別是應用的數量和最小需要釋放的記憶體。接下來一行輸入n個應用分別佔用的記憶體,再輸入一行,n個應用解除安裝時對應需要消耗的點數(點數只有1和2兩種)。
求:在滿足最小需要釋放的記憶體前提下,最少消耗的點數是多少。若不能達成前提條件,輸出-1。 - 思路:顯然,從點數只有1和2兩種入手,將所有的應用按1和2分開,又因為無論點數如何,記憶體佔用大的都有較大的解除安裝優先順序,即兩組資料都按降序排序。
再來,就到了這題的關鍵部分:
1、先分別對兩組資料進行字首和處理,以優化便於後續的二分查詢更新答案。
2、單對解除安裝消耗點數為1的資料進行遍歷,這是因為點數為1的應用在解除安裝上的優先順序要高於消耗點數為2的應用。
3、在對已經進行了字首和處理的資料遍歷過程下,處理方式為,①若當前的字首和已經滿足前提,直接對答案最小化更新當前的下標值。②當前的字首和值(X)不滿足的話,利用二分查詢函式lower_bound()在點數為2的字首和陣列中查詢大於等於m-X的最小下標,乘2處理再對答案更新即可。③還需注意,若不存在解除安裝消耗點數為1的應用 => 遍歷的這個陣列為空,直接二分函式對點數為2的字首陣列查詢大於等於m的最小下標。 - 程式碼:
#include<bits/stdc++.h>
#define ll long long
#define LL unsigned long long
#define up_b upper_bound
#define low_b lower_bound
#define all(a) begin(a),end(a)
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int maxn= 2e5+5;
ll a[maxn],b1[maxn],b2[maxn];
bool cmp(ll a,ll b){return a>b;}
void solve()
{
int n,m;cin>>n>>m;
ll sum=0;
for(int i=1;i<=n;i++)
cin>>a[i], sum+=a[i];
int b,n1=0,n2=0;
for(int i=1;i<=n;i++)
{
cin>>b;
if(b==1) b1[++n1]=a[i];
else b2[++n2]=a[i];
}
if(sum<m)
{
cout<<-1<<endl;
return ;
}
sort(b1+1,b1+1+n1,cmp);
sort(b2+1,b2+1+n2,cmp);
for(int i=2;i<=n1;i++) b1[i] += b1[i-1];
for(int i=2;i<=n2;i++) b2[i] += b2[i-1];
int ans = INF;
for(int i=0;i<=n1;i++)//零位開始,若b1陣列為空,直接對b2陣列UPB
{
if(b1[i]>=m) ans = min(ans,i);
else
{
int pos = low_b(b2+1,b2+1+n2,m-b1[i])-b2;
if(pos>n2) continue;
ans = min(ans,i+2*pos);
}
}
cout<<ans<<endl;
}
int main()
{
IOS;
int t;cin>>t;
while(t--){ solve(); }
return 0;
}
E. Advertising Agency
標籤:組合數學
- 題設:
- 思路:
- 程式碼:
#include<bits/stdc++.h>
#define ll long long
#define LL unsigned long long
#define mem(a,n) memset(a,n,sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
priority_queue <int,vector<int>,less<int> > QM;
const int INF= 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 1005;//
ll fac[maxn];
ll ex_gcd(ll a,ll b,ll &x,ll &y){//拓展歐幾里得
if(b==0){x = 1;y = 0;return a;}
ll ans = ex_gcd(b,a%b,x,y);
ll temp = x;
x = y;
y = temp - (a/b)*y;
return ans;
}
ll inv(ll a){//求逆元
ll x,y;
int ans = ex_gcd(a,mod,x,y);
if(ans!=1)return -1;
if(x<0)x = (x%mod+mod)%mod;
return x;
}
void init(){//求乘階
fac[0] = 1;
for(int i = 1;i<=maxn-1;i++){
fac[i] = (fac[i-1]*i)%mod;
}
}
ll comb(int n,int k){//求組合數
if(k>n)return 0;
return (fac[n]*inv(fac[k])%mod*inv(fac[n-k])%mod)%mod;
}
ll a[1010],n,k;
bool cmp(int a,int b){return a>b;}
void solve()
{
read(n);read(k);
for(int i=1;i<=n;i++) read(a[i]);
sort(a+1,a+1+n,cmp);
int numi=0,numa=0;
for(int i=1;i<=k;i++)
if(a[i]==a[k]) numa++;
for(int i=n;i>k;i--)
if(a[i]==a[k]) numi++;
cout<<comb(numi+numa,numa)<<endl;
}
int main()
{
IOS;
init();
int t;read(t);
while(t--){ solve(); }
return 0;
}