cf Round 633

A.Rebus(思维题)

给出一个这种形式的表达式 ? + ? - ? + ? = n.
要求用1-n的数字填充疑问号使等式成立,如果不存在这样的方式,则输出不可能。
存在则输出任意的方式。

移项可以变成?+?+?...=n+?+?+...的形式,可以求出等式左边和右边的取值范围,如果不相交则无解,然后贪心构造一下即可。

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <math.h>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define MAXN 10005
# define eps 1e-5
# define MAXM 1000005
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}

char s[500];
int vis[500], cnt=0, ans[500];

int main()
{
    int p, fu=0, zheng=1, n=0;
    gets(s);
    vis[0]=1;
    for (int i=2; ; i+=4) {
        if (s[i]=='=') {p=i; break;}
        else if (s[i]=='+') vis[++cnt]=1, zheng++;
        else if (s[i]=='-') vis[++cnt]=-1, fu++;
    }
    for (int i=p+2; s[i]; ++i) n=n*10+s[i]-'0';
    if (n*zheng<n+fu||n+fu*n<zheng) puts("Impossible");
    else {
        puts("Possible");
        if (n*zheng>=n+fu&&n+fu>=zheng) {
            int mod=(n+fu)%zheng;
            for (int i=0; i<=cnt; ++i) {
                if (vis[i]==-1) ans[i]=1;
                else {
                    ans[i]=(n+fu)/zheng;
                    if (mod) ans[i]++, mod--;
                }
            }
        }
        else {
            int mod=(zheng-n)%fu;
            for (int i=0; i<=cnt; ++i) {
                if (vis[i]==1) ans[i]=1;
                else {
                    ans[i]=(zheng-n)/fu;
                    if (mod) ans[i]++, mod--;
                }
            }
        }
        for (int i=0; i<=cnt; ++i) {
                if (i) printf(vis[i]==1?"+ ":"- ");
                printf("%d ",ans[i]);
            }
            printf("= %d\n",n);
    }
    return 0;
}
View Code

 

B.International Olympiad(思维题)

 

题意:给出每次奥林匹克的缩写,第一次是1989年,缩写为9,每次不能重复,
问给出n个询问,每个询问是一个缩写,问真实的年份是多少。

 

我们观察发现
1989-1998 占了个位数的全部
1999-2098 占了十位数的全部
2099-3098 占了百位数的全部
3099-13098 占了万位数的全部

 

于是我们可以找出规律,直接搞就行了。

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <math.h>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define MAXN 10005
# define eps 1e-5
# define MAXM 1000005
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}

char s[15];

int main ()
{
    int n;
    scanf("%d",&n);
    while (n--) {
        scanf("%s",s);
        int len=strlen(s+4), year=atoi(s+4), F=0, ten=10;
        FO(i,1,len) {
            F+=ten;
            ten*=10;
        }
        while (year<1989+F) year+=ten;
        printf("%d\n",year);
    }
    return 0;
}
View Code

 

C.Graph Coloring(二分图染色)

给出n个顶点,m条边的无向图(n,m<=1e5).
初始时每条边有一种颜色R或者B。
每操作一次可以选定一个点,并将该点邻接的边颜色全都取反,问至少需要多少次这样的操作可以将所有的边变成一种颜色。
如果不存在输出-1.

分析:
分为两种情况,要么最后边都是R,要么都是B
假设最后都会变成R,我们发现对于任意一个边(u,v),
如果边uv是R,那么u,v都需要操作一次,或者都不需要操作。
因为每一个顶点操作两次是没有必要的,所以我们可以发现对于每个顶点,要么不操作,要么操作一次。
于是我们可以把它们按操作数是否相等划分到S-T集合里面去,如果边uv是R,则u,v属于同一集合。如果边uv是B,则u,v属于不同的集合。
最后的答案就是S和T集合模的最小值。

如果图不连通,我们可以对他的强连通分量做。
于是问题就转化成了二分图染色了

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <math.h>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define MAXN 100005
# define eps 1e-5
# define MAXM 1000005
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}

struct Edge{int p, next, flag;}edge[MAXN<<1];
int head[MAXN], set[MAXN], cnt=1, ans1[MAXN], ans2[MAXN], num1, num2, node[MAXN], vis[MAXN];
int one, two;

void add_edge(int u, int v, char flag)
{
    int x=(flag=='R'?1:-1);
    edge[cnt].p=v; edge[cnt].next=head[u]; edge[cnt].flag=x; head[u]=cnt++;
    edge[cnt].p=u; edge[cnt].next=head[v]; edge[cnt].flag=x; head[v]=cnt++;
}
int find(int x)
{
    int s, temp;
    for (s=x; set[s]>=0; s=set[s]) ;
    while (s!=x) temp=set[x], set[x]=s, x=temp;
    return s;
}
void union_set(int x, int y)
{
    int temp=set[x]+set[y];
    if (set[x]>set[y]) set[x]=y, set[y]=temp;
    else set[y]=x, set[x]=temp;
}
bool dfs(int x, int mark)
{
    for (int i=head[x]; i; i=edge[i].next) {
        int v=edge[i].p;
        if (node[v]) {
            if (mark==edge[i].flag&&node[v]!=node[x]) return false;
            if (mark!=edge[i].flag&&node[v]==node[x]) return false;
            continue;
        }
        node[v]=(mark==edge[i].flag?node[x]:-node[x]);
        node[v]==1?one++:two++;
        if (dfs(v,mark)==0) return false;
    }
    return true;
}
void find1(int x, int flag)
{
    vis[x]=1;
    if (node[x]==flag) ans1[++num1]=x;
    for (int i=head[x]; i; i=edge[i].next) {
        int v=edge[i].p;
        if (vis[v]) continue;
        find1(v,flag);
    }
}
void find2(int x, int flag)
{
    vis[x]=1;
    if (node[x]==flag) ans2[++num2]=x;
    for (int i=head[x]; i; i=edge[i].next) {
        int v=edge[i].p;
        if (vis[v]) continue;
        find2(v,flag);
    }
}
int main ()
{
    int n, m, u, v;
    int flag1=1, flag2=1;
    scanf("%d%d",&n,&m);
    char s[3];
    mem(set,-1);
    while (m--) {
        scanf("%d%d%s",&u,&v,s);
        add_edge(u,v,s[0]);
        u=find(u); v=find(v);
        if (u!=v) union_set(u,v);
    }
    FOR(i,1,n) {
        if (set[i]<0) {
            node[i]=1; one=1, two=0;
            if (dfs(i,1)==0) {flag1=0; break;}
            if (one>two) find1(i,-1);
            else find1(i,1);
        }
    }
    mem(vis,0); mem(node,0);
    FOR(i,1,n) {
        if (set[i]<0) {
            node[i]=-1; one=0, two=1;
            if (dfs(i,-1)==0) {flag2=0; break;}
            if (one>two) find2(i,-1);
            else find2(i,1);
        }
    }
    if (flag1==0 && flag2==0) {puts("-1"); return 0;}
    if (flag1==0) num1=INF;
    else if (flag2==0) num2=INF;
    if (num1>num2) {
        printf("%d\n",num2);
        FOR(i,1,num2) printf("%d ",ans2[i]);
        putchar('\n');
    }
    else {
        printf("%d\n",num1);
        FOR(i,1,num1) printf("%d ",ans1[i]);
        putchar('\n');
    }
    return 0;
}
View Code

 

D.To Hack or not to Hack(枚举+DP)

显然可以hack的题数超过90时一定是第一名。
否则我们可以枚举每道题的基本分,确定好每题最多能hack多少人。从而可以确定我们的最终分数。
基本分一定时,hack人数当然越多越好。
令dp[i][a][b][c]表示前i个人A题hack了a次,B题hack了b次,C题hack了c次的最高排名。
若不能hack,或分数较少,则直接转移。否则枚举每题的hack状态进行转移即可。
复杂度O(6^3*(n+90*30^3*2^3))

# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <math.h>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define MAXN 100005
# define eps 1e-5
# define MAXM 1000005
# define MOD 1000000007
# define INF 1000000000
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int (i)=(a); (i)<=(n); ++(i))
# define FO(i,a,n) for(int (i)=(a); (i)<(n); ++(i))
# define bug puts("H");
# define lch p<<1,l,mid
# define rch p<<1|1,mid+1,r
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
typedef unsigned long long ULL;
int _MAX(int a, int b){return a>b?a:b;}
int _MIN(int a, int b){return a>b?b:a;}
int Scan() {
    int res=0, flag=0;
    char ch;
    if((ch=getchar())=='-') flag=1;
    else if(ch>='0'&&ch<='9') res=ch-'0';
    while((ch=getchar())>='0'&&ch<='9')  res=res*10+(ch-'0');
    return flag?-res:res;
}
void Out(int a) {
    if(a<0) {putchar('-'); a=-a;}
    if(a>=10) Out(a/10);
    putchar(a%10+'0');
}

int n, a[5005][3], sum[3], hack[3], cnt, dp[2][95][95][95], sco[6][2];

int cal(int x, int y, int z)
{
    if (sco[x][0]>sco[x][1]||sco[y][0]>sco[y][1]||sco[z][0]>sco[z][1]) return n-1;
    if (sum[0]-hack[0]>sco[x][1]||sum[1]-hack[1]>sco[y][1]||sum[2]-hack[2]>sco[z][1]) return n-1;
    if (sum[0]<sco[x][0]||sum[1]<sco[y][0]||sum[2]<sco[z][0]) return n-1;
    int h1=min(sum[0]-sco[x][0], hack[0]);
    int h2=min(sum[1]-sco[y][0], hack[1]);
    int h3=min(sum[2]-sco[z][0], hack[2]);
    int mysco=(h1+h2+h3)*100+(a[1][0]!=0)*(x+1)*500*(250-abs(a[1][0]))/250+(a[1][1]!=0)*(y+1)*500*(250-abs(a[1][1]))/250+(a[1][2]!=0)*(z+1)*500*(250-abs(a[1][2]))/250;
    int flag=0, tot=0;
    FOR(i,0,h1) FOR(j,0,h2) FOR(k,0,h3) dp[0][i][j][k]=INF;
    dp[0][0][0][0]=0;
    FOR(i,2,n) {
        int hesco=(a[i][0]!=0)*(x+1)*500*(250-abs(a[i][0]))/250+(a[i][1]!=0)*(y+1)*500*(250-abs(a[i][1]))/250+(a[i][2]!=0)*(z+1)*500*(250-abs(a[i][2]))/250;
        if (a[i][0]>=0&&a[i][1]>=0&&a[i][2]>=0) {
            if (hesco>mysco) tot++;
            continue;
        }
        else if (hesco<=mysco) continue;
        int wei=0;
        FOR(j,0,2) {
            if (a[i][j]<0) wei=wei*2+1;
            else wei<<=1;
        }
        FOR(q1,0,h1) FOR(q2,0,h2) FOR(q3,0,h3) dp[flag^1][q1][q2][q3]=INF;
        FOR(q1,0,h1) FOR(q2,0,h2) FOR(q3,0,h3) {
            if (dp[flag][q1][q2][q3]>n) continue;
            FOR(j,0,(wei>>2)&1) FOR(k,0,(wei>>1)&1) FOR(l,0,wei&1) {
                int shesco=(j==0&&a[i][0])*(x+1)*500*(250-abs(a[i][0]))/250+(k==0&&a[i][1])*(y+1)*500*(250-abs(a[i][1]))/250+(l==0&&a[i][2])*(z+1)*500*(250-abs(a[i][2]))/250;
                if (shesco>mysco) dp[flag^1][q1+j][q2+k][q3+l]=min(dp[flag^1][q1+j][q2+k][q3+l], dp[flag][q1][q2][q3]+1);
                else dp[flag^1][q1+j][q2+k][q3+l]=min(dp[flag^1][q1+j][q2+k][q3+l], dp[flag][q1][q2][q3]);
            }
        }
        flag^=1;
    }
    int ans=INF;
    FOR(i,0,h1) FOR(j,0,h2) FOR(k,0,h3) ans=min(ans, dp[flag][i][j][k]);
    return ans+tot;
}
int main ()
{
    scanf("%d",&n);
    FOR(i,1,n) {
        scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);
        FOR(j,0,2) sum[j]+=(a[i][j]!=0);
        if(i!=1) FOR(j,0,2) hack[j]+=(a[i][j]<0);
    }
    // 特判
    if (hack[1]+hack[2]+hack[0]>=90) {puts("1"); return 0;}
    // 每个范围的分数
    int P=1;
    FOR(i,0,4) sco[i][0]=n/(2*P)+1, sco[i][1]=n/P, P*=2;
    sco[5][0]=0, sco[5][1]=n/32;
    int ans=INF;
    FOR(i,0,5) FOR(j,0,5) FOR(k,0,5) ans=min(ans,cal(i,j,k));
    printf("%d\n",ans+1);
    return 0;
}
View Code

 

E.Binary Table(待填坑)

 

posted @ 2017-01-05 23:00  free-loop  阅读(140)  评论(0编辑  收藏  举报