emmmmm……..
发烧请假回家结果没有赶上qwq
这是第一场胡策题
由56级大佬们出题%%%
Problem 1 赛小城玩骰子
题目描述
众所周知,a和赛小城关系很好,赛小城经常与a交(gao)流(shi),今天一早,赛小城突发奇想,要和a玩骰子。
赛小城有一个骰子,如图1所示:
数字1在上方,数字2在South(南)方位,数字3在East(东)方位,每一对相反方位的数字之和是7,按照上述.数字5在North(北)方位,数字4在west(西)方位,数字6在下方,如图l所示.数字4,5,6在图1中是看不到的。
骰子的初始位置如图1所示.按照下列 6条规则旋转骰子,规则如图2和图3所示:
图2中所示的4条旋转规则是将骰子按照规则指定的方位旋转90度。图3中所示的2条旋转规则是将骰子沿水平方向分别向left(左)或Right(右)方位旋转90度
图3.旋转规则Left(左)、Right(右)
a想知道,从图1所示的方位开始,根据给定的一系列规别连续的旋转骰子.在该过程中位于上方的数字之和(其中包括图1所示的初始方位上的数字1),赛小城被a的问题难住了,于是他向学习OI的你求助,你能帮帮他吗?
输入描述
第一行输入一个整数n,表示执行旋转的总步数。
第2~n-1行分别输入6条旋转规则中6个方位中的一个
输出描述
一行输出旋转过程中位于骰子上方的数字之和
样例输入
5
North
North
East
South
West
样例输出
21
数据范围及提示
对于100 %的数据 n≤1000
正解:
模拟。
#include<iostream>
#include<cstdio>
using namespace std;
int n,ans=1;
int fro=2,beh=5,lef=4,rig=3,upp=1,dow=6;
inline void move(char k)
{
switch(k)
{
case('N'):
upp=fro;fro=dow;
beh=7-fro;dow=7-upp;
break;
case('E'):
rig=upp;upp=lef;
lef=7-rig;dow=7-upp;
break;
case('W'):
upp=rig;rig=dow;
dow=7-upp;lef=7-rig;
break;
case('S'):
fro=upp;upp=beh;
beh=7-fro;dow=7-upp;
break;
case('R'):
fro=rig;rig=beh;
lef=7-rig;beh=7-fro;
break;
case('L'):
rig=fro;fro=lef;
lef=7-rig;beh=7-fro;
break;
}
ans+=upp;
}
int main()
{
scanf("%d",&n);
while(n--)
{
char oper[6];
scanf("%s",&oper);
move(oper[0]);
}
printf("%d\n",ans);
return 0;
}
另一个版本emmm:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<cstdlib>
using namespace std;
const int max=0;
int m,n,k,tot,ans=1,UP=1,DOWN=6,FRONT=2,BACK=5,LEFT=4,RIGNT=3;
inline int read()
{
int num;
char ch;
while((ch=getchar())<'0'||ch>'9');
num=ch-'0';
while((ch=getchar())>='0'&&ch<='9') num=num*10+ch-'0';
return num;
}
inline void out(int x)
{
if(x>=10) out(x/10);
putchar(x%10+'0');
return;
}
int main()
{
freopen("touzi.in","r",stdin);
freopen("touzi.out","w",stdout);
n=read();
char c;
while((c=getchar())!=EOF)
{
if(c=='N')
{
int T=UP;
UP=FRONT,FRONT=DOWN,DOWN=BACK,BACK=T;
ans+=UP;
}
else if(c=='S')
{
int T=UP;
UP=BACK,BACK=DOWN,DOWN=FRONT,FRONT=T;
ans+=UP;
}
else if(c=='E')
{
int T=UP;
UP=LEFT,LEFT=DOWN,DOWN=RIGNT,RIGNT=T;
ans+=UP;
}
else if(c=='W')
{
int T=UP;
UP=RIGNT,RIGNT=DOWN,DOWN=LEFT,LEFT=T;
ans+=UP;
}
else if(c=='R')
{
int T=FRONT;
FRONT=RIGNT,RIGNT=BACK,BACK=LEFT,LEFT=T;
ans+=UP;
}
else if(c=='L')
{
int T=FRONT;
FRONT=LEFT,LEFT=BACK,BACK=RIGNT,RIGNT=T;
ans+=UP;
}
}
out(ans);
fclose(stdin);
fclose(stdout);
return 0;
}
T2:
Problem 2 赛小城玩游戏
题目描述
众所周知,赛小城是一个游戏发烧友。
国庆节快到了,L国流行起了一种简单的扫雷游戏,这个游戏规则和扫雷一样,如果某个格子没有雷,那么它里面的数字表示和它8连通的格子里面雷的数目。现在棋盘是n×2的,第一列里面某些格子是雷,而第二列没有雷。
由于第一列的雷可能有多种方案满足第二列的数的限制,赛小城成功拿下所有记录之后,向你发下战书。你的任务即根据第二列的信息确定第一列雷有多少种摆放方案。
输入描述
第一行为N,第二行有N个数,依次为第二列的格子中的数。
输出描述
一个数,即第一列中雷的摆放方案数。
样例输入
2
1 1
样例输出
2
数据范围及提示
对于40 %的数据 1<= N <= 20
对于100 % 的数据 1<= N <= 10000
正解:
由某个点的前一点的数字和前两点的雷可以确定这个点是否防雷。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int sz = 23333;
int b[sz],a[sz];
int n,ans;
inline void read(int &x)
{
x=0;
int fl=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{if(ch=='-') fl=-1;ch=getchar();}
while(ch>='0'&&ch<='9')
{x=x*10+ch-'0';ch=getchar();}
x*=fl;
}
inline bool check()
{
for(int i=1;i<=n;++i)
{
b[i+1]=a[i]-b[i]-b[i-1];
if(b[i+1]<0||b[i+1]>1) return 0;
}
if(b[n+1]!=0) return 0;
return 1;
}
inline void write(int x)
{
if(x < 0)
putchar('-'),x *= -1;
if(x / 10)
write(x / 10);
putchar(x % 10 + '0');
}
int main()
{
read(n);
for(int i=1;i<=n;++i)
read(a[i]);
if(a[1]==0)
ans+=check();
else if(a[1]==1)
{
b[1]=1;
ans+=check();
for(int j=1;j<=n;++j)
b[j]=0;
b[2]=1;
ans+=check();
}
else
{
b[1]=1;
b[2]=1;
ans+=check();
}
write(ans);
puts("");
return 0;
}
/*
只要第一个雷已经确定,那么后面所有的雷都是确定的,
用 a 表示第二列的数字;
用 b 表示第一列的雷,若为1则有雷,反之亦然
所以枚举b[1]
接下来 b[i] = a[i - 1] - b[i -1] - b[i - 2]
判断中间的情况是否合法
最后记得判断最后一个是否合法。
如果最后b[n]+b[n-1]<>a[n],那么就能说明这种方案出错了,无需计入累加器
*/
T3:
Problem 3 赛小城学游泳
题目描述
众所周知,赛小城是一个胸怀大志,对游泳情有独钟的美男子。
他第一次尝试游泳便是在广州的大海边。不知怎的,在沙滩上,由于古老东方的神秘力量,他被吸入了一个新的海底聚落。召唤他的是南海龙王,因为他想为自己选定一个继承人。但管理海底世界需要一定的组织能力。于是他为赛小城出了一个题:若有n个城市和m条单向道路,城市编号为1~n。每条道路连接两个不同的城市,n和m满足m <= n(n - 1)。给定两个城市a和b,可以给a到b的所有简单路(所有城市最多经过一次,包括起点和终点)排序:先按长度从小到大排序,长度相同时按照字典序从小到大排序。管理南海一直是赛小城儿时的梦,他的任务便是求出从a城市到b城市的第k短路。
作为一名社会主义的好青年,助他一臂之力是你义不容辞的责任。
输入描述
输入的第一行为两个正整数 n 和 m,表示有 n 种化学物质和 m 条单向边。
接下来 m 行,每行有 3 个正整数 x,y,z,表示从化学物质x和化学物质y之间的单向边长度为 z
接下来一行,包括三个整数,a,b,k 表示赛小城所在的位置 a,终点所在的位置 b,和 k
输出描述
如果赛小城能通过第 k 短路从 S 到达 E,输出一个正整数,为第 k 短路的长度,如果不能通过第 k短路到达 E,输出“-1”(不包括引号)
样例输入
2 2
1 2 5
2 1 4
1 2 2
样例输出
14
数据范围及提示
对于 30%的数据 k <= 2
对于 70%的数据 1 <= N <= 100, 0 <= M <= 1000 1 <= a, b <= N, 1 <= c <= 100,k <= 100
对于 100%的数据 1 <= N <= 1000, 0 <= M <= 100000 1 <= a, b <= N, 1 <= c <= 100,k<=1000
k短路模板。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int sz = 233333;
int h[sz],n,m,S,E,k;
bool vis[sz],flag;
int tot1,fir1[sz],nxt1[sz];
int tot,fir[sz],nxt[sz];
struct A
{
int pos;
int g;
bool operator < (const A &a) const
{
return g + h[pos] > a.g + h[a.pos];
}
};
struct ed{
int f,t,w;
}l[sz],l1[sz];
inline void build(int f,int t,int d)
{
l[++tot] = (ed){f,t,d};
nxt[tot] = fir[f];
fir[f] = tot;
}
inline void build1(int f,int t,int d)
{
l1[++tot1] = (ed){f,t,d};
nxt1[tot1] = fir1[f];
fir1[f] = tot1;
}
queue<int>q1;
void spfa()
{
memset(h,0x3f3f3f,sizeof(h));
q1.push(E);
h[E] = 0;
while(!q1.empty())
{
int u = q1.front();
vis[u] = 0;
q1.pop();
for(int i = fir1[u];i;i = nxt1[i])
{
int v = l1[i].t;
if(h[v] > h[u] + l1[i].w)
{
h[v] = h[u] + l1[i].w;
if(!vis[v])
{
vis[v]=1;
q1.push(v);
}
}
}
}
}
priority_queue<A>q;
void Astar()
{
/*
A t;t.pos=S,t.g=0;
q.push(t);
这里的写法和下面的那一行一样的
*/
q.push((A){S,0});
int cnt = 0;
while(!q.empty())
{
A u = q.top();
q.pop();
if(u.pos==E)
{
cnt ++;
if(cnt == k)
{
flag = 1;
printf("%d",u.g);
return;
}
}
for(int i = fir[u.pos];i;i = nxt[i])
{
int v = l[i].t;
q.push((A){v,u.g + l[i].w});
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
build(a,b,c);
build1(b,a,c);
}
scanf("%d%d%d",&S,&E,&k);
if(S==E) k++;
spfa();
Astar();
if(flag==0)
puts("-1");
return 0;
}
T4:
Problem 4 赛小城学数学
题目描述
众所周知,赛小城是一个爱打瞌睡的好学生。
这一天,他又在数学课上睡觉,这令数学老师忍无可忍。说是迟,那是快,数学老师一个箭步飞奔过去,敲醒了赛小城。并给出了一道极难的数学题,让他清醒一下。题意如下:从1 − N中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少。赛小城退役已久,码力不够犯了难。于是赛小城找到了你,作为一名OIer,你能帮帮他么?
输入描述
一个数 N
输出描述
一行一个整数代表答案对100000007取模之后的答案。
样例输入
7
样例输出
144
数据范围及提示
对于30%的数据,1≤N≤100。
对于50%的数据,1≤N≤5000。
对于70%的数据,1≤N≤〖10〗^5。
对于100%的数据,1≤N≤5×〖10〗^6。
数论,嗯,没有然后了。
分解质因数。
正解:
统计从1到N中每个质因数出现的次数,然后把每个质因数取它们的次数次幂(*还需要处理一下),然后相乘就是答案。
如样例:
1 2 3 4 5 6 7
其中,4=2*2 ;6=2*3 ;
质数有:2,3,5,7;
对应出现的次数:
2 -> 4(次)
3 -> 2(次)
5 -> 1(次)
7 -> 1(次)
*如果次数是奇数,则 次数– ,如果次数是偶数,则不变。
处理后得:
2 -> 4
3 -> 2
5 -> 0
7 -> 0
相乘得:(2^4)(3^2)(5^0)*(7^0)=144;
首先筛一下素数,然后对于1~N的每个数x,出现的次数可记为:f(x)=(N/x)+(N/x^2)+(N/x^3)+…+(N/x^k);
由此,可快速求得f(x);
然后快速幂、相乘、%,即可。
void ask_jc(int n)
{
p = 0;
int t = n;
for(int i = 1;i <= tot && prime[i] <= n;i ++)
{
int c = prime[i];
while(c <= n)
{
cnt[i] += t / c;
c *= c;
p = i;
}
}
}
标程:
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=5000005;
long long prime[maxn];
bool not_prime[maxn];
long long num[maxn];
long long mod=100000007;
long long ksm(long long a,long long b)
{
if(b==0) return 1ll;
if(b==1) return a%mod;
long long tmp=ksm(a,b/2)%mod;
if(b%2==0)
return ((tmp%mod)*(tmp%mod))%mod;
else
return ((((tmp%mod)*tmp)%mod)*(a%mod))%mod;
}
int main()
{
freopen("pow.in","r",stdin);
freopen("pow.out","w",stdout);
long long n;
int cnt=0;
long long ans=1;
scanf("%I64d",&n);
not_prime[1]=true;
for(long long i=2;i<=n;i++)
{
if(!not_prime[i])
prime[++cnt]=i;
for(int j=1;j<=cnt;j++)
{
if(prime[j]*i>n) break;
not_prime[prime[j]*i]=true;
if(i%prime[j]==0) break;
}
}
for(int i=1;i<=cnt;i++)
{
long long aa=n;
while(aa!=0)
{
num[i]+=aa/prime[i];
aa/=prime[i];
}
}
for(int i=1;i<=cnt;i++)
{
if(num[i]%2==0)
ans=(ans*ksm(prime[i],num[i]))%mod;
else
ans=(ans*ksm(prime[i],num[i]-1))%mod;
}
printf("%I64d",ans);
return 0;
}