ハッピーアケ、アケはDIV3を持っています
コンテスト接続:https://codeforces.com/contest/1462
このゲームはとてもシンプルです。
目次
A.好きなシーケンス
本旨:
シーケンスを指定して、質問の順序でシーケンスを左右に出力します
質問のアイデア:
水の質問、質問の意味に従ってシミュレートします
コード:
ll n,m,p;
ll a[maxn];
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);
for(int i=1;i<=n;i++) read(a[i]);
int l = 1,r = n;
while(l<r){
printf("%lld %lld ",a[l],a[r]);
l++;
r--;
}
if(l == r) printf("%lld\n",a[l]);
else printf("\n");
}
return 0;
}
B.昨年の部分文字列
本旨:
数字の文字列を入力し、部分文字列を最大で1回削除して、最終的な文字列を「2020」にすることができるかどうかを尋ねます。
質問のアイデア:
最大で1つの操作を検討してください。削除できるのは中央の部分文字列だけなので、境界を判断するだけです。
コード:
ll n,m,p;
char s[maxn];
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);
scanf("%s",s+1);
if(n<4) printf("NO\n");
else{
if(s[1] == '2' && s[2] == '0' && s[3] == '2' && s[4] == '0') printf("YES\n");
else if(s[1] == '2' && s[2] == '0' && s[3] == '2' && s[n] == '0') printf("YES\n");
else if(s[1] == '2' && s[2] == '0' && s[n-1] == '2' && s[n] == '0') printf("YES\n");
else if(s[1] == '2' && s[n-2] == '0' && s[n-1] == '2' && s[n] == '0') printf("YES\n");
else if(s[n-3] == '2' && s[n-2] == '0' && s[n-1] == '2' && s[n] == '0') printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
C.一意の番号
本旨:
桁の合計がxに等しく、桁が互いに異なるかどうかを尋ねます。最小の数です。
質問のアイデア:
数値が異なることを考慮すると、合計で2の10乗が可能です。
バイナリで列挙するだけです
コード:
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);
int ans = 1e9+7;
for(int i=0;i<(1<<10);i++){
int res = 0,temp = 0;
for(int k=0;k<10;k++){
if(i>>k&1){
res += k;
a[++temp] = k;
}
}
if(res == n){
if(a[1] == 0) swap(a[1],a[2]);
int tempx = 0;
for(int k=1;k<=temp;k++) tempx = tempx*10+a[k];
ans = min(ans,tempx);
}
}
printf("%d\n",ans == mod?-1:ans);
}
return 0;
}
D.ネイバーに追加して削除する
本旨:
要約:シーケンスが与えられたら、各セグメントの合計が等しくなるように、分割できるセグメントの数を尋ねます。
最終的な答えは次のとおりです。n-セグメントの数
質問のアイデア:
最終状態の合計を直接考慮するという簡単な考え方があり、この合計は合計の因数でなければなりません
一人一人をチェックするだけです
合計が大きい場合はどうなるでしょうか。
これは、sとは関係のない区間dpを記述する方法です。考え方は非常に単純です。dp[i] [k]は、k個のセグメントに分割された最初のiの等しい値を表すと考えてください。
次に、n ^ 3の暴力を取得し、マップを使用して最適化します
これは私を非常に馬鹿にします。
コード:
ll n,m,p;
ll num[maxn],sum[maxn];
int dp[3005][3005];
int pre[3005];
unordered_map<ll,int>mp[3005];
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);
for(int i=1;i<=n;i++) {
read(num[i]);
sum[i] = sum[i-1]+num[i];
mp[i].clear();
}
int mx = 1;
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++)
dp[i][k] = -1;
for(int i=1;i<=n;i++){
dp[i][1] = sum[i];
for(int k=2;k<=i;k++){
int op = mp[k-1][sum[i]];
if(op) dp[i][k] = sum[i]-sum[op];
}
for(int k=1;k<=i;k++)
if(~dp[i][k]) mp[k][dp[i][k]+sum[i]] = i;
}
for(int i=n,k=0;i>=1;i--,k++){
if(dp[n][i]!=-1){
printf("%d\n",k);
break;
}
}
}
return 0;
}
E2。タプルを閉じる(ハードバージョン)
本旨:
長さnのシーケンスが与えられた場合、シーケンスの最大値-シーケンスの最小値<= kを満たす長さmのサブシーケンスの数を尋ねます。
質問のアイデア:
最終回答の最小値を列挙し、組み合わせの数を判断します
現在の列挙の最小値がxであると仮定すると、[x、x + k]がいくつあるかを知る必要があります。この操作は、ダブルポインターを使用して実行することもできます。ツリー配列を単純に記述するために、あなたがそれを考えるならば、結果は2つに分けることができます..
次に、それぞれ最小値の数を列挙します
コード:
ll n,m,p;
ll num[maxn];
ll sum[maxn];
int vis[maxn];
ll fac[maxn];
ll qpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}return ans;
}
ll cal(int m,int n){
if(m<n) return 0;
return ((fac[m]*qpow(fac[m-n],mod-2))%mod*(qpow(fac[n],mod-2))%mod)%mod;
}
void add(int pos){
while(pos <= n){
sum[pos] ++;
pos += pos&-pos;
}
}
ll GetSum(int pos){
ll ans = 0;
while(pos){
ans += sum[pos];
pos -= pos&-pos;
}return ans;
}
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);read(m);read(p);
for(int i=1;i<=n;i++) read(num[i]);
for(int i=1;i<=n;i++) sum[i] = 0,vis[i] = 0;
for(int i=1;i<=n;i++) vis[num[i]]++;
fac[0] = 1;
for(int i=1;i<=n;i++) fac[i] = (fac[i-1]*i)%mod;
for(int i=1;i<=n;i++) add(num[i]);
ll ans = 0;
for(int i=1;i<=n;i++){
if(vis[i]){
ll temp = GetSum(min(i+p,n)) - GetSum(i-1);
for(int k=1;k<=min(m,vis[i]*1ll);k++){
ans = (ans + (cal(vis[i],k)*cal(temp-vis[i],m-k))%mod)%mod;
}
}
}
printf("%lld\n",ans);
}
return 0;
}
F.セグメントの宝物
本旨:
他のすべての線分と交差する線分がある場合にのみ、適切な線分セットを定義します。少なくともいくつかの線分を削除して、この線分セットを適切なものにします。
質問のアイデア:
明らかなアイデアは、どの線分がこの線分セットを適切にするかを列挙することです。
したがって、線分と交差するために必要な線分は、[総数-この線分と交差する線分の数]を使用します。これは、ばらばらの線分の数です。
最後に、各線分の答えについては、1分かかります
座標が大きすぎて、椅子ツリーを使用してポイントを動的に開くため、この質問を行う方法はたくさんあります(離散化するには怠惰すぎます)
コード:
/*** keep hungry and calm CoolGuang! ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 2e5+700;
const int mod= 1e9+7;
const int up = 1e9;
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 a,b;
bool friend operator<(node a,node b){
if(a.a == b.a) return a.b < b.b;
return a.a < b.a;
}
}q[maxn];
int pre[maxn],suf[maxn];
ll sum[maxn];
int cnt = 0;
struct Tree{
int l,r,w;
}t[maxn*35];
int root[maxn];
void Insert(int &now,int pre,ll l,ll r,ll pos){
t[now = ++cnt] = t[pre];
t[now].w ++;
if(l == r) return ;
ll mid = (l+r)/2;
if(pos <= mid) Insert(t[now].l,t[pre].l,l,mid,pos);
else Insert(t[now].r,t[pre].r,mid+1,r,pos);
}
int Find(int now,ll l,ll r,ll x,ll y){
if(x<=l && y>=r) return t[now].w;
ll mid = (l+r)/2;
int ans = 0;
if(x<=mid) ans += Find(t[now].l,l,mid,x,y);
if(y>mid) ans += Find(t[now].r,mid+1,r,x,y);
return ans;
}
int main(){
int T;scanf("%d",&T);
while(T--){
read(n);
for(int i=1;i<=n;i++){
read(q[i].a);
read(q[i].b);
}
sort(q+1,q+1+n);
cnt = 0;
root[0] = 0;
for(int i=1;i<=n;i++){
pre[i] = Find(root[i-1],1,2e9,q[i].a,q[i].b);
Insert(root[i],root[i-1],1,2e9,q[i].b);
}
cnt = 0;
root[n+1] = 0;
for(int i=n;i>=1;i--){
suf[i] = Find(root[i+1],1,2e9,q[i].a,q[i].b);
Insert(root[i],root[i+1],1,2e9,q[i].a);
}
ll ans = INF;
for(int i=1;i<=n;i++)
ans = min(ans,n-1-pre[i]-suf[i]);
printf("%lld\n",ans);
}
return 0;
}