今天的题比较简单
T1 数学题
令 A,B,C 为三个质数(A≤B≤C) ,N=A∗B∗C 。
给出 N ,求 B。
考试思路
将N分解即可,分解到的第二个质因数即为B
#include<bits/stdc++.h>
using namespace std;
long long n;
int cnt=0,ans=0;
int main()
{
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
cin>>n;
for(int i=2;i<=sqrt(n*1.0);i++)
{
if(n%i==0)
{
if(cnt==1)
{
ans=i;
break;
}
n/=i;
cnt++;
i-=1;
}
}
cout<<ans;
return 0;
}
T2 方块转换
一块N x N(1<=N<=10)正方形的黑白瓦片的图案要被转换成新的正方形图案。写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式: 1:转90度:图案按顺时针转90度。 2:转180度:图案按顺时针转180度。 3:转270度:图案按顺时针转270度。 4:反射:图案在水平方向翻转(以中央铅垂线为中心形成原图案的镜像)。 5:组合:图案在水平方向翻转,然后再按照1到3之间的一种再次转换。 6:不改变:原图案不改变。 7:无效转换:无法用以上方法得到新图案。 如果有多种可用的转换方法,请选择序号最小的那个。
考试思路
按照题意模拟即可,但是没看到输出序号最小,错了一组
#include<bits/stdc++.h>
using namespace std;
int n;
char a[20][20],b[20][20],c[20][20];
void turn()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
b[i][j]=a[n-j+1][i];
}
void copy()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
a[i][j]=b[i][j];
}
bool equal()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(a[i][j]!=c[i][j]) return 0;
return 1;
}
void reflect()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
b[i][j]=a[i][n-j+1];
}
int main()
{
freopen("transform.in","r",stdin);
freopen("transform.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
scanf("%s",a[i]+1);
for(int i=1;i<=n;i++)
scanf("%s",c[i]+1);
turn();copy();
if(equal()) {cout<<1;return 0;}
turn();copy();
if(equal()) {cout<<2;return 0;}
turn();copy();
if(equal()) {cout<<3;return 0;}
turn();copy();
reflect();copy();
if(equal()) {cout<<4;return 0;}
turn();copy();
if(equal()) {cout<<5;return 0;}
turn();copy();
if(equal()) {cout<<5;return 0;}
turn();copy();
if(equal()) {cout<<5;return 0;}
turn();copy();
reflect();copy();
if(equal())
{
cout<<6;
return 0;
}
cout<<7;
return 0;
}
T3 凯妹的考验
2014 年,凯妹代表中国队参加了在南非举行的第 55 届的 IMO(International
Mathematical Olympiad,即国际数学奥林匹克)。赛场上,凯妹留了一道几何傻题给你:
一共N条线段,然后给出 M 个操作。描述如下:
1 a b:表示 a 直线平行 b 直线
2 a b:表示 a 直线垂直 b 直线
3 a b:询问 a 直线和 b 直线的关系,如果平行输出‘Z’,垂直输出‘J’,都有可能输出‘K’。(若
a=b,则默认为平行)。
如果凯妹在过程中胡乱口胡你(即与前面给出的关系发生冲突),请直接输出
‘ORZKsister’,不要输出其余内容。请快点A掉它,这样凯妹会对你好感++
输入描述
解题思路
拓展域并查集裸题
#include<bits/stdc++.h>
using namespace std;
int fa[200600],ans[200600],top=0;
int n,m,opt,a,b;
int Find(int x)
{
if(x==fa[x]) return x;
return fa[x]=Find(fa[x]);
}
bool flag=0;
int main()
{
freopen("imo.in","r",stdin);
freopen("imo.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=2*n;i++)
fa[i]=i;
while(m--)
{
scanf("%d%d%d",&opt,&a,&b);
if(opt==1)
{
if(Find(a+n)==Find(b))
{
flag=1;
break;
}
else if(Find(a)!=Find(b))
{
fa[Find(a)]=Find(b);
fa[Find(a+n)]=Find(b+n);
}
}
else if(opt==2)
{
if(Find(a)==Find(b))
{
flag=1;
break;
}
else if(Find(a)!=Find(b+n))
{
fa[Find(a)]=Find(b+n);
fa[Find(a+n)]=Find(b);
}
}
else
{
if(Find(a)==Find(b)) ans[++top]=0;
else if(Find(a)==Find(b+n)) ans[++top]=1;
else ans[++top]=2;
}
}
if(flag==1)
{
printf("ORZKsister\n");
return 0;
}
for(int i=1;i<=top;i++)
{
if(ans[i]==0) printf("Z\n");
if(ans[i]==1) printf("J\n");
if(ans[i]==2) printf("K\n");
}
return 0;
}
T4 博弈
群哥来到了飞来峰,发现有两位神人在顶上对弈。棋盘长成下图的模样:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
每个点都有一个编号:由上到下,由左到右,依次编号为 1、2……12。两位神人轮流博
弈,每一轮操作的一方可以取走一个棋子,或者取走相邻的两个棋子(即在同一直线上相邻
的棋子)。取走最后一颗棋子的人输。
给定初始状态(有些位置没有棋子),如果两个人都采取最优决策,问谁能赢。
考试思路
一眼状压,但是既然题目叫做博弈,那么……
直接有向图游戏求出每个局面的SG函数值,最后判断即可
#include<bits/stdc++.h>
using namespace std;
const int N = (1<<13)+7;
const int M = 5e5+7;
struct node
{
int y,next;
}e[2*M];
int link[N],t=0;
void add(int x,int y)
{
if(y==0) return;
e[++t].y=y;
e[t].next=link[x];
link[x]=t;
}
int G[13][13];
int SG[N];
int mex[N][120];
bool vis[N];
void pre()
{
G[1][4]=G[4][1]=1;
G[2][5]=G[5][2]=1;
G[3][4]=G[4][3]=1;
G[4][5]=G[5][4]=1;
G[5][6]=G[6][5]=1;
G[4][8]=G[8][4]=1;
G[5][9]=G[9][5]=1;
G[7][8]=G[8][7]=1;
G[8][9]=G[9][8]=1;
G[9][10]=G[10][9]=1;
G[8][11]=G[11][8]=1;
G[9][12]=G[12][9]=1;
}
int S=(1<<12)-1,n;
int pos(int k)
{
return 1<<(k-1);
}
int cnt=0;
void dfs(int x)
{
cnt++;
if(vis[x]) return;
for(int i=link[x];i;i=e[i].next)
{
int y=e[i].y;
dfs(y);
mex[x][SG[y]]=1;
}
for(int i=0;i<=120;i++)
{
if(mex[x][i]==0)
{
SG[x]=i;
break;
}
}
vis[x]=1;
}
char s[20];
int ans[1200],top=0;
int main()
{
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
pre();
for(int i=1;i<=S;i++)
{
for(int k=1;k<=12;k++)
{
if((i>>(k-1))&1)
add(i,i-pos(k));
}
for(int j=1;j<=12;j++)
for(int k=j+1;k<=12;k++)
if(((i>>(j-1))&1)&&((i>>(k-1))&1)&&G[j][k]&&(j!=k))
add(i,i-pos(j)-pos(k));
}
dfs(S);
scanf("%d",&n);
while(n--)
{
scanf("%s",s+1);
int st=0;
for(int i=12;i>=1;i--)
st=st*2+s[i]-'0';
if(st==0) ans[++top]=0;
else if(SG[st]>0) ans[++top]=0;
else ans[++top]=1;
}
for(int i=1;i<=top;i++)
cout<<ans[i];
return 0;
}
T5 收集果子
体面略
考试思路
虽然看出是树上背包计数但是我对这东西不是很通透,于是推了个错的DP式,爆0了
正解
稍微改改就对了,但是是N^3枚举的会超时,这是某位wmz大佬的话响起
这种树上背包一般卡卡上界就能变成了N^2了
然后
就没了
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1200;
const int mod=1e9+7;
struct node
{
int y,next;
}e[2*N];
int link[N],val[N],t=0;
void add(int x,int y)
{
e[++t].y=y;
e[t].next=link[x];
link[x]=t;
}
LL F[N][N],siz[N],G[N],sum[N];
LL n,K;
LL power[N];
void dfs(int x,int pre)
{
F[x][val[x]]=1;
siz[x]=1;
sum[x]=val[x];
for(int i=link[x];i;i=e[i].next)
{
int y=e[i].y;
if(y==pre) continue;
dfs(y,x);
siz[x]+=siz[y];
sum[x]+=sum[y];
for(LL j=0;j<=min(sum[x],K);j++)
{
G[j]=F[x][j]*power[siz[y]-1]%mod;
for(LL k=0;k<=min(j,sum[y]);k++)
G[j]=(G[j]+F[x][j-k]*F[y][k]%mod)%mod;
}
for(int j=0;j<=min(sum[x],K);j++)
F[x][j]=G[j];
}
}
int main()
{
freopen("fruit.in","r",stdin);
freopen("fruit.out","w",stdout);
scanf("%lld%lld",&n,&K);
for(int i=1;i<=n;i++)
scanf("%lld",&val[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
power[0]=1;
for(int i=1;i<=n;i++)
power[i]=power[i-1]*2%mod;
dfs(1,0);
cout<<F[1][K];
return 0;
}