1. 程式人生 > 其它 >Codeforces Round #690 (Div. 3)——解題報告

Codeforces Round #690 (Div. 3)——解題報告

技術標籤:codeforce演算法

比賽連結:https://codeforces.com/contest/1462

A題——Favorite Sequence

根據題意直接模擬即可。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 3e2+7;
int a[N];
void solve(){
    int n=read();
    rp(i,1,n) a[i]=read();
    int l=1,r=n;
    int f=1;
    int cnt=0;
    while(l<=r){
        if(f==1) cout<<a[l++],cnt++;
        else cout<<a[r--],cnt++;
        f^=1;
        if(cnt==n) cout<<endl;
        else cout<<" ";
    }
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

B題——Last Year's Substring

暴力的想法是直接列舉刪除[i,j]區間判斷就行了,然後可以發現當i確定後,j也就隨之確定,這樣就可以省掉一個迴圈,而且易知i的長度也不能大於4(優化),簡化後也就是題解的做法。

trick:樣例已經給出了的2020的情況。

比較好寫且簡單的做法(題解):因為2020的長度為4,所以刪除區間的長度為n-4,那麼最終區間的可能也就定了,總共五種。

s_{0}s_{1}s_{2}s_{3},s_{0}s_{1}s_{2}s_{n-1},s_{0}s_{1}s_{n-2}s_{n-1},s_{0}s_{n-3}s_{n-2}s_{n-1},s_{n-4}s_{n-3}s_{n-2}s_{n-1}

判斷他們是否等於2020就行了。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
void solve(){
    int n=read();
    string s;cin>>s;
    rp(i,0,3){
        if(s.substr(0,i)+s.substr(n-4+i,4-i)=="2020"){
            puts("YES");
            return ;
        }
    }
    puts("NO");
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

C題——Unique Number

我的做法是直接手算,因為n最大才50,而大於等於45的都是不行的(這一點應該不難推出)。

手推構造一下可以得出(至於怎麼構造的,請參考題解

當n<=9時,答案就是n,19,29,...,89最多可以表示到17,189,289,...,789最多可以表示到24,之後的類推就行了,發現上界為123456789,最多表示為45。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
void solve(){
    int x=read();
    if(x>45) printf("-1\n");
    else{
        if(x<=9) printf("%d",x);
        else if(x<=17) printf("%d9",x-9);
        else if(x<=24) printf("%d89",x-17);
        else if(x<=30) printf("%d789",x-24);
        else if(x<=35) printf("%d6789",x-30);
        else if(x<=39) printf("%d56789",x-35);
        else if(x<=42) printf("%d456789",x-39);
        else if(x<=44) printf("%d3456789",x-42);
        else if(x==45) printf("123456789");
        printf("\n");
    }     
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();
    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

D題——Add to Neighbour and Remove

假設當前操作次數為i

因為每次操作都只是改變數所在集合的位置,那麼總和就是不變的,而且要求i次操作後每個集合元素和相等,因此每個集合的元素和就確定了,為sum/(n-i)。

什麼情況下i合法呢,根據上面可知,當(n-i)為sum的因子時是合法的。

這樣我們就可以列舉合法的操作次數,再貪心地從前往後維護每個集合就行了,最後判斷當前操作次數是否能夠滿足要求就行了。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 3e3+7;
int a[N];
void solve(){
    int n=read();
    int sum=0;
    rp(i,1,n) a[i]=read(),sum+=a[i];
    rp(i,0,n-1){
        if(sum%(n-i)!=0) continue;
        int res=sum/(n-i);
        int ff=0;
        int cur=0;
        int cnt=0;
        rp(j,1,n){
            if(cur+a[j]>res){
                ff=1;
                break;
            }
            else if(cur+a[j]==res){
                cur=0;
                cnt++;
            }
            else cur+=a[j];
        }
        if(cnt!=n-i) ff=1;
        // cout<<i<<" "<<ff<<endl;
        if(ff==0){
            cout<<i<<endl;
            break;
        } 
    }
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

E題——Close Tuples

感覺比D題好想一點,屬於比較套路的題,第一眼還以為是三維偏序的題,最後發現是一道二分的簡單題。

首先我們需要對a陣列排個序,然後對於每個ai進行考慮,即先給集合選一個數。

先二分出最後一個小於等於ai+k的數的位置id。

在[i+1,id]中選出m-1個數(即\textrm{C}^{m-1}_{id-i})和ai湊成m個數就行了。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 2e5+7;
const ll mod = 1e9+7;
int a[N];
ll fac[N];
ll quickPow(ll a, ll b, ll mod) {
	ll ans = 1;
	while(b) {
		if(b&1) ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
ll inv(ll x){
	return quickPow(x,mod-2,mod);
}
ll C(int n,int m){
	return fac[n]*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
void init(){
	fac[0]=1;
	rp(i,1,N-7) fac[i]=(fac[i-1]*i)%mod;
}
void solve(){
	int n=read(),m=read(),k=read();
	rp(i,1,n) a[i]=read();
	sort(a+1,a+1+n);
	ll ans=0;
	rp(i,1,n){
		int id=upper_bound(a+1,a+1+n,a[i]+k)-a;
		id--;
		id=min(id,n);
		if(id-i>=m-1) ans=(ans+C(id-i,m-1)%mod)%mod;
	}
	cout<<ans<<endl;
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	time_t beg, end;
	//if(debug) beg = clock();
	init();
	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}

F題——The Treasure of The Segments

題意可以轉換成求最少的區間不相交數(以當前區間和幾個其他區間不相交)。

這樣就好辦了,兩個區間[l1,r1]和[l2,r2]不相交的情況:r1<l2或者r2<l1.

而這兩種情況不會重複,因此我們可以直接對左端點和右端點進行排序,二分枚舉出兩種情況的答案後,把兩種情況的答案加起來維護最小值就行了。

怎麼二分呢?我們假設當前區間是[l,r]。

我們二分出所有區間中小於l的最大右端點id1(利用lower_bound實現),那麼這種情況的答案就是id1

然後再二分出所有區間中大於r的最小左端點id2(利用upper_bound實現),那麼這種情況的答案就是n-id2+1.

答案就是所有區間的id1+n-id2+1的最小值。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}
inline int read(){
	int s=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=s*10+ch-'0';
		ch=getchar();
	}
	return s*f;
}
const int N = 2e5+7;
struct node{
	int l,r;
}p[N];
struct edge{
	int x,type;
};
vector<int> data;
vector<int> L,R;
void init() { data.clear();L.clear();R.clear();}
void Ins(int val) { data.push_back(val); }
void doit() {
	sort(data.begin(), data.end());
	data.erase(unique(data.begin(), data.end()), data.end());
}
int g(int val) { return lower_bound(data.begin(), data.end(), val) - data.begin() + 1; }
void solve(){
	int n=read();
	init();
	rp(i,1,n) p[i].l=read(),p[i].r=read(),Ins(p[i].l),Ins(p[i].r);
	doit();
	rp(i,1,n) p[i].l=g(p[i].l),p[i].r=g(p[i].r);
	rp(i,1,n) L.p_b(p[i].l),R.p_b(p[i].r);
	int ans=n+1;
	sort(L.begin(),L.end());
	sort(R.begin(),R.end());
	rp(i,1,n){
		int cur=lower_bound(R.begin(),R.end(),p[i].l)-R.begin()+1;
		cur--;
		cur+=max(0,n-(upper_bound(L.begin(),L.end(),p[i].r)-L.begin()+1)+1);
		ans=min(ans,cur);
	}
	cout<<ans<<endl;
}
int main(){
	//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
	freopen("in.txt", "r", stdin);
	//debug = 1;
#endif
	time_t beg, end;
	//if(debug) beg = clock();

	int T=read();
	while(T--) solve();

	/*
	if(debug) {
		end = clock();
		printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
	}
	*/
	return 0;
}