Codeforces Round #630 (Div. 2) 补题


A. Exercising Walk
指定各个移动方向的移动次数,终点就是确定的,所以只要判断终点在不在范围之内,多余的步数让猫反复横跳就行了。要注意如果边界x1==x2,那么猫就不能左右移动,y轴也同理

代码
#pragma GCC optimize(2)
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#define INF 1e18
#define x first
#define y second
typedef long long ll;
using namespace std;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int q;
int a,b,c,d;
int x,y,lx,rx,dy,uy;
int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    read(q);
    while(q--){
        cin>>a>>b>>c>>d;
        cin>>x>>y>>lx>>dy>>rx>>uy;
        x+=b-a;
        y+=d-c;
        if(lx==rx&&(a||b)){
            printf("NO\n");
        }
        else if(uy==dy&&(c||d)){
            printf("NO\n");
        }
        else if(x<=rx&&x>=lx&&y<=uy&&y>=dy){
            printf("YES\n");
        }
        else printf("NO\n");
    }
    return 0;
}

B. Composite Coloring
前十一个素数分别是2,3,5,7,11,13,17,19,23,29,31,因为a的范围是小于一千,所以数组中的任何一个数分解因数后一定包含前十一个素数中的某个,否则这个数至少是37*39>1000。所以我们可以根据前十一个素因数对数组进行划分。

代码
#pragma GCC optimize(2)
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#define INF 1e18
#define x first
#define y second
typedef long long ll;
using namespace std;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int prime[11]={2,3,5,7,11,13,17,19,23,29,31};
int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int q;
    read(q);
    while(q--){
        int n,cnt=0;
        read(n);
        vector<int> a(n);
        vector<int> ans(n);
        vector<int> vis(11);
        set<int> color;
        for(int i=0;i<n;i++) read(a[i]);
        for(int i=0;i<n;i++){
            bool flag=true;
            for(int j=0;j<11;j++){
                if(!ans[i]&&a[i]%prime[j]==0){
                    if(!vis[j]){
                        vis[j]=++cnt;
                    }
                    ans[i]=vis[j];
                    color.insert(j);
                    break;
                }
            }
        }
        printf("%d\n",color.size());
        for(int i=0;i<n;i++) printf("%d ",ans[i]);
        putchar('\n');
    }
    return 0;
}



C. K-Complete Word
题目中说明了n能被k整除,所以这个字符串可以被划分为n/k块,每块长度是k。根据题目给的规则可以推出对于i<k/2,每块中第i个位置和第k-i+1个位置的元素是相同的,这n/k块中的一共2*n/k个元素是相同的,只要找到这2*n/k个元素中出现次数最多的字母,个数是res,那么就需要改变2*n/k-res个元素。遍历每个位置即可

写的有点乱
#pragma GCC optimize(2)
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#define INF 1e18
#define x first
#define y second
typedef long long ll;
using namespace std;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int q;
string s;
int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    read(q);
    while(q--){
        int n,k;
        read(n),read(k);
        cin>>s;
        int blo=n/k;
        int ans=0;
        for(int i=0;i<k/2;i++){
            map<char,int> l;
            int res=0;
            for(int j=0;j<n;j+=k){
                l[s[j+i]]++;
                
                res=max(res,l[s[j+i]]);
            }
            for(int j=k-1;j<n;j+=k){
                l[s[j-i]]++;
                res=max(res,l[s[j-i]]);
            }
            ans+=2*blo-res;
        }
        if(k%2==1){
            int res=0;
            map<char,int> l;
            for(int i=k/2;i<n;i+=k){
                l[s[i]]++;
                res=max(res,l[s[i]]);
            }
            ans+=blo-res;
        }
        cout<<ans<<endl;
    }
    return 0;
}

D. Walk on Matrix
使用dp的错误之处在于,每一步都追求最优解不一定能使最终结果最优,比如
217+k,217, 0
k,217+k,k
中,dp(2,2)我们得到的值是217,这样最终结果是0。而事实上,在(2,2)处,选择a[2][2]&a[2][1]使dp(2,2)值为k,可以得到最终结果为k,与dp所得结果相差k。
题中说n和m自选,所以所有询问都可以根据这个例子构造2*3的矩阵。

代码
#pragma GCC optimize(2)
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#define INF 1e18
#define x first
#define y second
typedef long long ll;
using namespace std;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int k;
    read(k);
    int a[2][3]={(1<<17)+k,1<<17,0,k,(1<<17)+k,k};
    cout<<"2 3"<<endl;
    for(int i=0;i<2;i++){
        for(int j=0;j<3;j++){
            printf("%d ",a[i][j]);
        }
        putchar('\n');
    }
    return 0;
}


E. Height All the Same
用每个格子上方块的个数表示这个方块的奇偶性。
第一种操作的效果是可以使所有奇偶性相同的格子达到同样的值。第二种操作的效果是让任意两个格子同时改变奇偶性,因为如果格子u到v的路径是uabv,那么只需要通过第二种操作使得(u+1,a+1)->(a+1+1,b+1)->(b+1+1,v+1)。所以我们只需要把所有奇数格子变成偶数或者把所有偶数格子变成奇数格子即可。
如果n*m是奇数,我们一定可以达到目标。因为在这种情况下如果有奇数个奇数格子,我们只需要把剩下偶数个偶数格子两两变成奇数格子即可,如果有奇数个偶数格子同理。
如果n*m是偶数,那么只能是奇数个格子是奇数,奇数个格子是偶数,或者偶数个格子是偶数,偶数个格子是奇数。即方块数和为偶数。只要统计出每个格子上放奇数个方块和放偶数个方块的方案数,之后的操作类似于高中的排列组合。

代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
ll mod = 998244353;

ll mod_pow(ll x,ll n)
{
    ll res=1;
    while(n){
        if(n&1) res=res*x%mod;
        x=x*x%mod;
        n>>=1;
    }
    return res;
}

ll n,m,l,r;
int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    cin>>n>>m>>l>>r;
    if((n*m)&1){
        cout<<mod_pow(r-l+1,n*m);
    }
    else{
        ll x,y;
        x=y=(r-l+1)/2;
        if((r-l+1)&1){
            if(l&1) x++;
            else y++;
        }
        cout<<(mod_pow(x+y,n*m)+mod_pow(y-x,n*m))*mod_pow(2,mod-2)%mod;
    }
    return 0;
}

F. Independent Set
本题求树的边的子集中的独立集的个数,采用动态规划的做法,对点进行染色,假设染色的点在一个独立子集中。dp[u][0]是u的子树中,u不染色的方案总数。dp[u][1]是u的子树中,u染色的所有情况。dp[u][2]是u的子树中,u和所有儿子不连接的情况下的方案总数。
状态转移时,假设儿子v不与u连接时,v的子树中方案总数f[v]=dp[v][0]+dp[v][1]-dp[v][2],不减去dp[v][2]的话就可能会把v是孤立点的情况包含进去。于是就有
dp[u][0]*=dp[v][1]+dp[v][0]+f[v](v是u的儿子)
dp[u][1]*=dp[v][0]+f[v]
dp[u][2]*=f[v]
最终结果要减1,除去空集的情况。

代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
inline void read(int &p)
{
    p=0;int flag=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
    while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
ll mod = 998244353;
vector<int> e[300005];
int n;
ll dp[300005][3];
void dfs(int f,int u){
    for(int i=0;i<=2;i++) dp[u][i]=1;
    for(int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(v==f) continue;
        dfs(u,v);
        dp[u][0]*=(2*dp[v][0]%mod+2*dp[v][1]%mod-dp[v][2]+mod)%mod;
        dp[u][0]%=mod;
        dp[u][1]*=(2*dp[v][0]%mod+dp[v][1]-dp[v][2]+mod)%mod;
        dp[u][1]%=mod;
        dp[u][2]*=(dp[v][0]+dp[v][1]-dp[v][2]+mod)%mod;
        dp[u][2]%=mod;
    }
}
int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    read(n);
    for(int i=1;i<n;i++){
        int u,v;
        read(u),read(v);
        e[u].push_back(v);
        e[v].push_back(u);
    }
    dfs(-1,1);
    cout<<(dp[1][0]+dp[1][1]-dp[1][2]-1+mod)%mod;
    return 0;
}

posted @ 2020-04-01 21:48  DinoMax  阅读(231)  评论(0)    收藏  举报