AtCoder Beginner Contest 190 | 全题解

鸽了建模队友的一晚,悄悄地写个 a t c o d e r atcoder atcoder没人发现吧?

悄悄地 a k ak ak,不让他们发现

AtCoder Beginner Contest 190

  • A.Very Very Primitive Game
    • 题目大意:
    • 题目思路:
    • Code:
  • B.Magic 3
    • 题目大意:
    • 题目思路:
    • Code:
  • C.Bowls and Dishes
    • 题目大意:
    • 题目思路:
    • Code:
  • D.Staircase Sequences
    • 题目大意:
    • 题目思路:
    • Code:
  • E.Magical Ornament
    • 题目大意:
    • 题目思路:
    • Code:
  • F.Shift and Inversions
    • 题目大意:
    • 题目思路:
    • Code:

A.Very Very Primitive Game

题目大意:

题目思路:

略(水题)

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include 
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e5+700;
const int M = 1e6+8;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
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;}
ll n,m,p;
int main(){
     
	ll a,b,c;read(a);read(b);read(c);
	if(c == 0){
     
		if(a>b) printf("Takahashi\n");
		else printf("Aoki\n");
	}else{
     
		if(b>a) printf("Aoki\n");
		else printf("Takahashi\n");
	}
    return 0;
}

/**
**/

B.Magic 3

题目大意:

判断当前给出 s , t s,t s,t中是否存在 s < S s \lt S s<S, t < D t \lt D t<D的物品

题目思路:

水题

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include 
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e5+700;
const int M = 1e6+8;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
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;}
ll n,m,p;
int main(){
     
	ll S,D;
	read(n);read(S);read(D);
    int f = 0;
    for(int i=1;i<=n;i++){
     
    	int x,y;read(x);read(y);
    	if(x<S && y>D) f = 1;
    }
    printf("%s\n",f?"Yes":"No");
    return 0;
}

/**

5
N 83 2 7475
UN 83 2 27550
EXF 5 2 17298
OVYNH 51 2 14827
XNV 53 1 7591
2
1
XNV
2
83
**/

C.Bowls and Dishes

题目大意:

现在有 N N N个盘子

给出一些条件 ( A i , B i ) (A_i,B_i) (Ai,Bi),这个条件被满足当且仅当 A i , B i A_i,B_i Ai,Bi盘子中都有一件物品

现在有 K K K个人,可以向 C i , D i C_i,D_i Ci,Di中放一个物品,不能同时放只能放一个,问最多能满足几个条件?

题目思路:

主要考虑到 K ≤ 17 K \le 17 K17,所以直接暴力枚举 K K K的状态就好了

复杂度: O ( N ∗ 2 K ) O(N*2^K) O(N2K)

暴力判断每个状态的结果,最后求最优就好了。

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include 
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e6+700;
const int M = 2e5+8;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
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;}
ll n,m,p;
struct node{
     
	int x,y;
}q[maxn];
ll dp[maxn][20];///前i个线段形成以K结尾时最小长度
ll c[maxn];
ll w[maxn][2];
int vis[maxn];
int main(){
     
	read(n);read(m);
	for(int i=1;i<=m;i++){
     
		read(q[i].x);
		read(q[i].y);
	}
	read(p);
	for(int i=0;i<p;i++){
     
		read(w[i][0]);
		read(w[i][1]);
	}
	int MAX = (1<<p);
	int ans = 0;
	for(int i=0;i<MAX;i++){
     
		for(int k=0;k<p;k++){
     
			int op = (i>>k&1);
			vis[w[k][op]] = 1;
		}
		int res = 0;
		for(int k=1;k<=m;k++){
     
			if(vis[q[k].x] && vis[q[k].y])
				res++;
		}
		ans = max(ans,res);
		for(int k=1;k<=n;k++) vis[k] = 0;
	}
	di(ans);
    return 0;
}

/**

5
N 83 2 7475
UN 83 2 27550
EXF 5 2 17298
OVYNH 51 2 14827
XNV 53 1 7591
2
1
XNV
2
83
**/

D.Staircase Sequences

题目大意:

询问有多少公差为1的序列的是 N N N

题目思路:

公式题,首先看见数据范围 N ≤ 1 e 12 N \le 1e12 N1e12,考虑直接根号分解

推一下公式:

假设存在一段序列 [ l + 1 , r ] [l+1,r] [l+1,r]和是 N N N,那么满足:

r ∗ ( r + 1 ) 2 − l ∗ ( l + 1 ) 2 = N \frac{r*(r+1)}{2} - \frac{l*(l+1)}{2} = N 2r(r+1)2l(l+1)=N

r ∗ ( r + 1 ) − l ∗ ( l + 1 ) = 2 ∗ N r*(r+1)-l*(l+1)=2*N r(r+1)l(l+1)=2N

r ∗ r − l ∗ l + r − l = 2 ∗ N r*r - l*l +r-l = 2*N rrll+rl=2N

( r − l ) ∗ ( r + l ) + ( r − l ) = 2 ∗ N (r-l)*(r+l)+(r-l) = 2*N (rl)(r+l)+(rl)=2N

( r − l ) ∗ ( r + l + 1 ) = 2 ∗ N (r-l)*(r+l+1) = 2*N (rl)(r+l+1)=2N

根号分解因子,之后判断即可

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include 
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e5+700;
const int M = 1e6+8;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
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;}
ll n,m,p;
map<pair<ll,ll>,int>mp;
int main(){
     
	read(n);
	n*=2;
	ll ans = 0;
	for(ll i=1;i*i<=n;i++){
     
		if(n%i == 0){
     
			ll tempx = i,tempy = n/i;
			if((tempx+tempy-1)%2==0){
     
				ll r = (tempx+tempy-1)/2;
				ll l = (r-tempx);
				if(!mp[{
     l,r}]){
     
					mp[{
     l,r}] = 1;
					ans ++;
				}
			}
			tempy = i,tempx = n/i;
			if((tempx+tempy-1)%2==0){
     
				ll r = (tempx+tempy-1)/2;
				ll l = (r-tempx);
				if(!mp[{
     l,r}]){
     
					mp[{
     l,r}] = 1;
					ans ++;
				}
			}
		}
	}
	dl(ans);
    return 0;
}

/**

5
N 83 2 7475
UN 83 2 27550
EXF 5 2 17298
OVYNH 51 2 14827
XNV 53 1 7591
2
1
XNV
2
83
**/

E.Magical Ornament

题目大意:

给你 M M M个相连的数对,在生成的序列中只能用 M M M个相连的数对连接(数对不考虑顺序)。

给出 K K K个数,问包含K个数的 最小的 可以连接的 序列长度是多少

题目思路:

首先可以将数抽象为点,那么以 s s s开始以 t t t结束最少的序列长度,就可以由最短路求出。

所以首先预处理 K K K个点之间两两之间的最短路。

有了这个之后,观察K的范围 K ≤ 17 K \le 17 K17,所以直接最小权值哈密尔顿回路就好了.

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include 
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e16+7;
const ll maxn = 1e6+700;
const int M = 2e5+8;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
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;}
ll n,m,p;
ll dis[maxn];
struct N{
     
    int id;
    ll w;
    bool friend operator<(N a,N b)
    {
     
        return a.w>b.w;
    }
};
vector<pair<int,int>>v[maxn];
void dijstra(int st){
     
    for(int i=1;i<=n;i++) dis[i]=INF;
    dis[st]=0;
    N s;s.id=st;s.w=0;
    priority_queue<N>q;
    q.push(s);
    while(!q.empty()){
     
        N u=q.top();q.pop();
        if(dis[u.id]!=u.w) continue;
        for(auto x:v[u.id]){
     
            int e = x.first,w = x.second;
            if(dis[e]>u.w+w){
     
                dis[e]=u.w+w;
                N now;now.id=e;
                now.w=dis[e];
                q.push(now);
            }
        }
    }
    return ;
}
ll c[maxn];
ll mp[20][20];
ll s[20][1<<18];
int main(){
     
	read(n);read(m);
	for(int i=1;i<=m;i++){
     
		int x,y;read(x);read(y);
		v[x].push_back({
     y,1});
		v[y].push_back({
     x,1});
	}
	read(p);
	for(int i=1;i<=p;i++) read(c[i]);
	for(int i=1;i<=p;i++){
     
		dijstra(c[i]);
		for(int k=i+1;k<=p;k++){
     
			mp[i-1][k-1] = mp[k-1][i-1] = dis[c[k]];
		}
	}
	int MAX = 1<<p;
    for(int i=0;i<p;i++)
    	for(int k=0;k<MAX;k++)
    		s[i][k] = INF;
   	for(int i=0;i<p;i++) s[i][1<<i] = 0;
   	
   	for(int i=1;i<MAX;i++){
     
   		for(int k=0;k<p;k++){
     
   			for(int j=0;j<p;j++){
     
   				if(j == k) continue;
   				if(i>>j&1) continue;
   				s[j][i|(1<<j)] = min(s[j][i|(1<<j)],s[k][i]+mp[k][j]);
   			}
   		}
   	}
   	ll ans = INF;
   	for(int i=0;i<p;i++)
   		ans = min(ans,s[i][MAX-1]);
   	if(ans>=INF) printf("-1\n",ans);
   	else printf("%lld\n",ans+1);
    return 0;
}

/**

5
N 83 2 7475
UN 83 2 27550
EXF 5 2 17298
OVYNH 51 2 14827
XNV 53 1 7591
2
1
XNV
2
83
**/

F.Shift and Inversions

题目大意:

初始给出一个序列 N N N,可以看成一个环。

输出 N N N行:

i i i行代表从 i i i开始 N N N个数字的序列逆序对数。

题目思路:

首先将i = 1的逆序对数求出

观察接下来的变化,每次移动都是将第1个放到最后

也就是说:

  1. 减少小于它的数字个数的逆序对数:因为他要放到最后,之前比他大的都要减少 1 1 1
  2. 增加大于它的数字个数的逆序对数:因为他要放到最后,前面的比他大的要增加 1 1 1

问题就解决啦。

Code:

/*** keep hungry and calm CoolGuang!  ***/
//#pragma GCC optimize(3)
#include 
#include
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"<
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e18+7;
const ll maxn = 1e5+700;
const int M = 1e6+8;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
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;}
ll n,m,p;
ll a[maxn];
ll sum[maxn];
void add(int pos){
     
	while(pos<=n){
     
		sum[pos]++;
		pos += pos&-pos;
	}
}
ll query(int pos){
     
	ll ans = 0;
	while(pos){
     
		ans += sum[pos];
		pos -= pos&-pos;
	}return ans;
}
int main(){
     
	read(n);
	for(int i=1;i<=n;i++){
     
		read(a[i]);
		a[i]++;
	}
	ll ans = 0;
	for(int i=1;i<=n;i++){
     
		ans += query(n)-query(a[i]);
		add(a[i]);
	}
	dl(ans);
	for(int i=1;i<=n;i++){
     
		ans += query(n)-query(a[i])-query(a[i]-1);
		dl(ans);
	}
    return 0;
}

/**

5
N 83 2 7475
UN 83 2 27550
EXF 5 2 17298
OVYNH 51 2 14827
XNV 53 1 7591
2
1
XNV
2
83
**/

你可能感兴趣的:(AtCoder Beginner Contest 190 | 全题解)