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; }
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;
}
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;
}
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;
}
E.Binary Table(待填坑)