1. 程式人生 > 其它 >Codeforces Round #697 (Div. 3)

Codeforces Round #697 (Div. 3)

技術標籤: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;
}