【Codeforces Round #547 (Div. 3) 】 A.B.C.D.E.F1.F2.G

전언
biubiu-biu r a t i n g + = 162 rating+=162 rating+=162 1500->1662
A. Game 23
제목의 뜻
nn, mmm를 두 개 세어 드릴게요. 매번 nn을 22에 곱하거나 33에 곱할 수 있어요. 몇 번 조작하면 nn이 mm로 변할 수 있어요.출력할 수 없습니다.
방법
우선 정제 여부를 판단한 뒤 사업자를 꾸준히 222/3으로 나눈 뒤 최종 판정 결과가 111이면 된다.
코드
#include
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    if(m%n!=0||m<n)
    {
        printf("-1");
        return 0;
    }
    int tmp=m/n;
    int cnt=0;
    while(tmp%2==0)
    {
        tmp/=2;
        cnt++;
    }
    while(tmp%3==0)
    {
        tmp/=3;
        cnt++;
    }
    if(tmp!=1) printf("-1
"
); else printf("%d
"
,cnt); return 0; }

B. Maximal Continuous Rest
제목의 뜻
길이가 nn인 010101열로 구성된 고리를 드리겠습니다. 고리의 가장 긴 연속인 111이 얼마나 긴지 물어보세요.
방법
제목에 따라 시뮬레이션하면 된다.
코드
#include
#include
#include
using namespace std;
const int maxn = 2e5+5;
int a[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==1)
        {
            int cnt=0;
            while(i<=n&&a[i]==1)
            {
                i++;
                cnt++;
            }
            ans=max(ans,cnt);
            i--;
        }
    }
    int tmp=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]==1) tmp++;
        else break;
    }
    for(int i=n;i>=1;i--)
    {
        if(a[i]==1) tmp++;
        else break;
    }
    ans=max(ans,tmp);
    printf("%d
"
,ans); return 0; }

C. Polycarp Restores Permutation
제목의 뜻
길이 nn의 수조 차분 후의 수조를 드리겠습니다.원수 그룹이 1대-n 1-n 1대-n의 배열이냐고 물었다.
방법
우선 우리는 고정된 수조 중의 첫 번째 수가 있으면 수조를 복원할 수 있다는 것을 알 수 있다. 또한 원수조가 [1,n][1,n][1,n]배열이면 복원된 수조는 반드시 [k,k+n-1][k,k+n-1][k,k+n-1]의 배열이기 때문에 복원된 수조가 만족하는지 판단하면 된다.아래 표지가 경계를 넘지 않도록 주의해라.
코드
#include
#include
#include
using namespace std;
const int maxn = 2e5+5;
const int INF = 0x3f3f3f3f;
int a[maxn];
int vis[maxn];
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n-1;i++) scanf("%d",&a[i]);
    int minn=INF,maxx=-INF;
    a[0]=0;
    for(int i=1;i<=n-1;i++)
    {
        a[i]=a[i-1]+a[i];
        minn=min(minn,a[i]);
        maxx=max(maxx,a[i]);
    }
    minn=min(minn,0);
    maxx=max(maxx,0);
    if(maxx-minn+1==n)
    {
        for(int i=0;i<=n-1;i++) a[i]=a[i]+(1-minn);
        for(int i=0;i<=n-1;i++)
        {
            if(vis[a[i]])
            {
                printf("-1
"
); return 0; } vis[a[i]]=1; } for(int i=0;i<=n-1;i++) printf("%d ",a[i]); } else printf("-1
"
); return 0; }

D. Colored Boots
제목의 뜻
n n n 길이의 문자열 두 개를 드리겠습니다. 문자 집합은 소문자와 ? 입니다.두 문자가 일치하는 조건은 두 문자가 같거나 그 중 한 문자가 ?인 것이다.두 문자열에 최대 몇 쌍의 문자가 일치하는지 물어보십시오.
방법
우선 두 문자가 같고 소문자가 직접 일치하면 낭비하지 않는다?.이후 양쪽은 각각 ?로 나머지 소문자를 매칭하고, 마지막으로 양쪽?이 모두 남으면 두 개?로 매칭한다.
코드
#include
#include
#include
#include
using namespace std;
typedef pair <int, int> pii;
const int maxn =2e5+5;
#define Se second
#define Fi first
#define pb push_back
int sum[2][27];
char str1[maxn],str2[maxn];
vector<int> tt[2][27];
vector<pii> ansv;
int main()
{
    //ios::sync_with_stdio(false);
    //freopen("a.txt","r",stdin);
    //freopen("b.txt","w",stdout);
    int n;
    scanf("%d",&n);
    scanf("%s",str1);
    scanf("%s",str2);
    for(int i=0;i<n;i++)
    {
        if(str1[i]=='?')
        {
            tt[0][26].push_back(i+1);
            sum[0][26]++;
        }
        else
        {
            tt[0][str1[i]-'a'].pb(i+1);
            sum[0][str1[i]-'a']++;
        }
    }
     for(int i=0;i<n;i++)
    {
        if(str2[i]=='?')
        {
            tt[1][26].push_back(i+1);
            sum[1][26]++;
        }
        else
        {
            tt[1][str2[i]-'a'].pb(i+1);
            sum[1][str2[i]-'a']++;
        }
    }
    int ans=0;
    int cnt1=0,cnt2=0;
    for(int i=0;i<26;i++)
    {
        ans+=min(sum[0][i],sum[1][i]);
        int tmp=min(sum[0][i],sum[1][i]);
        int ty=min(tt[0][i].size(),tt[1][i].size());
        for(int j=tt[0][i].size()-1,k=tt[1][i].size()-1;j>=0&&k>=0;j--,k--)
        {
            ansv.push_back(pii(tt[0][i][j],tt[1][i][k]));
            tt[0][i].pop_back();
            tt[1][i].pop_back();
        }
    }
    for(int i=0;i<26;i++)
    {
        if(tt[0][i].size()>0)
        {
            int tq=tt[0][i].size()-1;
            while(sum[1][26]>0&&tq>=0)
            {
                sum[1][26]--;
                ans++;
                ansv.push_back(pii(tt[0][i][tq],tt[1][26][sum[1][26]]));
                tq--;
            }
        }
        if(tt[1][i].size()>0)
        {
            int tq=tt[1][i].size()-1;
            while(sum[0][26]>0&&tq>=0)
            {
                sum[0][26]--;
                ans++;
                ansv.push_back(pii(tt[0][26][sum[0][26]],tt[1][i][tq]));
                tq--;
            }
        }
    }
    while(sum[0][26]>0&&sum[1][26]>0)
    {
        sum[0][26]--;
        sum[1][26]--;
        ans++;
        ansv.push_back(pii(tt[0][26][sum[0][26]],tt[1][26][sum[1][26]]));
    }
    printf("%d
"
,ans); for(int i=0;i<ans;i++) printf("%d %d
"
,ansv[i].Fi,ansv[i].Se); return 0; }

E. Superhero Battle
제목의 뜻
초기 혈액량이 HH인 몬스터가 있는데 그의 혈액 변화 상황은 길이 nn바퀴의 주기이다.몬스터가 몇 라운드에서 죽는지 물어봐.
1 ≤ H ≤ 1 0 12 1\leq H\leq 10^{12} 1≤H≤1012 1 ≤ n ≤ 2 × 1 0 5 1\leq n\leq 2\times 10^5 1≤n≤2×105 방법
우선 몬스터의 혈액량이 한 주기 내에 0 0 0 보다 작지 않고 매 주기 이후 몬스터의 혈액량이 증가하면 직접 출력 - 1 - 1 - 1 - 1 - 1 을 출력한다.이후에 몬스터가 어떤 완전한 주기 전에 x혈액량에 도달하면 몬스터가 이 바퀴를 버티지 못한다는 것을 알아야 한다.이 xxx의 구법은 주기를 한 번 훑어보고 어느 순간에 몬스터의 혈액량이 가장 많이 소모되는 것을 찾는 것이다.이후 몬스터의 초기 혈액량을 H -3 x H-x H -3 x로 가정하자.몬스터가 몇 개의 완전한 바퀴를 지탱할 수 있는지를 보고, 여기에 바퀴 수를 kk로 설정하면, 매 라운드 몬스터의 혈액량이 sum sum sum 감소하면, sum를 만족시켜야 한다.× k + x ≥ H sum\times k+x\ge H sum×k+x≥Hk≥H-3 x s u m k\ge\rac{H-x} {sum} k≥sumH-3 x 그러므로 부등식 오른쪽에서 kk를 추출하여 정돈한 다음에 O(n)O(n)O(n)의 주기로 몬스터가 몇 라운드에서 죽는 것을 보면 된다.코드
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 2e5+5;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
int a[maxn];
int n;
ll H;
ll sum;
int check(ll mid)
{
    ll tt=H;
    tt+=(mid-1)*sum;
    if(tt<=0) return 0;
    for(int i=1;i<=n;i++)
    {
        tt+=a[i];
        if(tt<=0) return i;
    }
    return -1;
}
int main()
{
    scanf("%lld%d",&H,&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sum=0;
    int flag=0;
    ll tmp=H;
    ll minn=LL_INF;
    int pos;
    for(int i=1;i<=n;i++)
    {
        sum+=a[i];
        tmp+=a[i];
        if(sum<minn)
        {
            minn=sum;
            pos=i;
        }
        if(tmp<=0)
        {
            flag=i;
            break;
        }
    }
    if(flag!=0)
    {
        printf("%d
"
,flag); return 0; } if(sum>=0) { printf("-1"); return 0; } minn=-minn; sum=-sum; ll ans=(H-minn)/sum+((H-minn)%sum!=0); H=H-ans*sum; if(H==0) { printf("%lld
"
,ans*n); return 0; } for(int i=1;i<=n;i++) { H+=a[i]; if(H<=0) { printf("%lld
"
,ans*n+i); return 0; } } return 0; }

F1.F2. Same Sum Blocks
제목의 뜻
너에게 길이가 n인 수조를 하나 주고, 가능한 한 많은 교차하지 않는 구간을 찾아내고, 그들의 구간은 서로 같다.
1 ≤ n ≤ 1500 1\leq n\leq 1500 1≤n≤1500
방법
n=1500n=1500n=1500n=1500으로 인해 구간은 1500에 불과하다× 1500 1500\times 1500 1500×1500가지이기 때문에 우리는 이 구간과 최종 답안으로서 각 구간과 많은 구간을 얻을 수 있다. 각 구간과 문제는 n개의 구간에서 가장 많은 교차하지 않는 구간을 찾아내는 문제로 전환된다. 이 문제는 r순서에 따라 욕심을 내어 왼쪽에서 오른쪽으로 선택하면 된다. 그 다음에 각 구간과 답안을 maxmax max로 하면 이 문제를 완성할 수 있다.
코드
#include
#include
#include
#include
#include
#include
using namespace std;
typedef pair <int, int> pii;
const int maxn = 1e6+5;
#define pb push_back
#define Se second
#define Fi first
int a[maxn];
vector<pii> anss;
vector<pii>tmp;
map<int,int> r;
unordered_map<int,vector<pii>>  mp;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) a[i]=a[i-1]+a[i];
    int ans=1;
    anss.push_back(pii(1,1));
    vector<int> rr;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=i;j++)
        {
            int tmp=a[i]-a[j-1];
            if(r.find(tmp)==r.end()||r[tmp]<j)
            {
                mp[tmp].pb(pii(j,i));
                r[tmp]=i;
            }
        }
    }
    for(unordered_map<int,vector<pii> >::iterator it=mp.begin();it!=mp.end();++it)
    {
        if((*it).Se.size()>ans)
        {
            ans=(*it).Se.size();
            anss=(*it).Se;
        }
    }
    printf("%d
"
,ans); for(int i=0;i<ans;i++) printf("%d %d
"
,anss[i].Fi,anss[i].Se); return 0; }

G. Privatization of Roads in Treeland
제목의 뜻
nn의 결점을 가진 나무 한 그루를 드리겠습니다. 지금은 각 변을 염색해야 합니다. 만약에 한 노드가 연결된 변의 색깔이 똑같다면 이 점은 나쁜 점입니다. 지금 나쁜 점의 개수가 kkk를 넘지 않도록 하려면 최소한 몇 가지 색깔로 변을 염색해야 하는지 물어보세요.
방법
우선 이것은 나무이기 때문에 두 개의 점마다 한 변만 영향을 받기 때문에 각 점의 염색은 독립적이라고 볼 수 있다.각 변마다 최소한 한 가지 색을 염색하기 때문에 이 변을 어떻게 염색하는지는 다른 점에 영향을 주지 않는다. 이후에 우리는 욕심스럽게 도수가 가장 큰 kk개의 점을 선택하여 이 점을 포기하고 임의의 점부터 dfsdfsdfs로 염색하면 된다.포기하지 않는 점에 대해 그는 모든 하위 노드와 부모 노드의 모서리 색깔과 같지 않다.포기한 점에 대해서는 모두 같은 색으로 염색하면 된다.마지막으로 통계는 최대 몇 가지 색깔을 사용했다.
코드
#include
#include
#include
#include
using namespace std;
typedef pair <int, int> pii;
const int maxn = 2e5+5;
#define Fi first
#define Se second
#define pb push_back
struct data
{
    int pos;
    int ind;
}x[maxn];
vector<pii>G[maxn];
bool cmp(const data &a,const data &b)
{
    if(a.ind==b.ind) return a.pos<b.pos;
    return a.ind>b.ind;
}
int vis[maxn];
int ans[maxn];
void dfs(int rt,int fa,int col)
{
    int tmp=0;
    for(int i=0;i<G[rt].size();i++)
    {
        int to=G[rt][i].Fi;
        int id=G[rt][i].Se;
        if(to==fa) continue;
        if(vis[rt]==1)
        {
            ans[id]=1;
            dfs(to,rt,1);
        }
        else
        {
            if(++tmp==col) tmp++;
            ans[id]=tmp;
            dfs(to,rt,tmp);
        }
    }
}
int main()
{
    int n,k,u,v;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n-1;i++)
    {
        scanf("%d%d",&u,&v);
        G[u].pb(pii(v,i));
        G[v].pb(pii(u,i));
        x[u].ind++;
        x[v].ind++;
    }
    for(int i=1;i<=n;i++) x[i].pos=i;
    sort(x+1,x+1+n,cmp);
    for(int i=1;i<=k;i++) vis[x[i].pos]=1;
    dfs(1,-1,-1);
    int maxx=0;
    for(int i=1;i<=n-1;i++) maxx=max(maxx,ans[i]);
    printf("%d
"
,maxx); for(int i=1;i<=n-1;i++) printf("%d ",ans[i]); return 0; }

좋은 웹페이지 즐겨찾기