2017.9.16队内互测——老年组Day1
出题人:feather,MeiCo,Summer,Black
Problem 1:
对于100%的数据,n<=1000
截图比较奇怪…还请见谅
简单的模拟题…但要注意题目中的左右翻转与实际情况是相反的
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
int n,p,tmp;
int num[1010][1010];//北1南2西3东4下5
ll ans;
char c[1010];
int main()
{
freopen("touzi.in","r",stdin);
freopen("touzi.out","w",stdout);
scanf("%d",&n);
num[1][1]=5;
num[1][2]=2;
num[1][3]=4;
num[1][4]=3;
num[1][5]=6;
ans+=1;
p=1;
for(int i=1;i<=n;i++)
{
scanf("%s",&c);
if(c[0]=='N')
{
tmp=p;
p=num[tmp][2];
num[p][1]=tmp;
num[p][2]=num[tmp][5];
num[p][3]=num[tmp][3];
num[p][4]=num[tmp][4];
num[p][5]=num[tmp][1];
ans+=p;
}
if(c[0]=='S')
{
tmp=p;
p=num[tmp][1];
num[p][1]=num[tmp][5];
num[p][2]=tmp;
num[p][3]=num[tmp][3];
num[p][4]=num[tmp][4];
num[p][5]=num[tmp][2];
ans+=p;
}
if(c[0]=='W')
{
tmp=p;
p=num[tmp][4];
num[p][1]=num[tmp][1];
num[p][2]=num[tmp][2];
num[p][3]=tmp;
num[p][4]=num[tmp][5];
num[p][5]=num[tmp][3];
ans+=p;
}
if(c[0]=='E')
{
tmp=p;
p=num[tmp][3];
num[p][1]=num[tmp][1];
num[p][2]=num[tmp][2];
num[p][3]=num[tmp][5];
num[p][4]=tmp;
num[p][5]=num[tmp][4];
ans+=p;
}
if(c[0]=='R')
{
tmp=num[p][1];
num[p][1]=num[p][3];
num[p][3]=num[p][2];
num[p][2]=num[p][4];
num[p][4]=tmp;
ans+=p;
}
if(c[0]=='L')
{
tmp=num[p][1];
num[p][1]=num[p][4];
num[p][4]=num[p][2];
num[p][2]=num[p][3];
num[p][3]=tmp;
ans+=p;
}
}
printf("%I64d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
Problem 2:
考虑第二列的格子中有且仅有0,1,2三种数字,确定起始位置数字后递推验证方案即可,或者搜索处理
//递推版本
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,ans;
int num[1000010],bomb[1000010];
int check()
{
for(int i=1;i<=n;i++)
{
bomb[i+1]=num[i]-bomb[i]-bomb[i-1];
if(bomb[i]<0||bomb[i]>1)
return 0;
}
if(bomb[n+1]!=0)
return 0;
else return 1;
}
int main()
{
freopen("mine.in","r",stdin);
freopen("mine.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
if(num[1]==0)
ans+=check();
if(num[1]==1)
{
bomb[1]=1;
ans+=check();
memset(bomb,0,sizeof(bomb));
bomb[2]=1;
ans+=check();
}
if(num[1]==2)
{
bomb[1]=1;
bomb[2]=1;
ans+=check();
}
printf("%d",ans);
fclose(stdin);
fclose(stdout);
return 0;
}
以下搜索版本学习借鉴自http://my.youkuaiyun.com/loi_lxt十分感谢(虽然没发在博客上)
//搜索版本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,num[100010];
long long dfs(int now,int x,int y)
{
if(now==n)
{
if(x+y==num[n])
return 1;
else return 0;
}
long long ans=0;
if(x+y+1==num[now]&&x+1<=num[now+1])
ans+=dfs(now+1,1,x);
if(x+y==num[now]&&x<=num[now+1])
ans+=dfs(now+1,0,x);
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
if(num[1]==1)
printf("%lld",dfs(1,1,0)+dfs(1,0,0));
else if(num[1]==2)
printf("%lld",dfs(2,1,1));
else if(num[1]==0)
printf("%lld",dfs(2,0,0));
else if(num[1]==3) printf("0");
return 0;
}
Problem 3:
题目排版是有问题…就是求第k短路啦..A*写起来比较麻烦就写了Dijkstra,第k次找到终点的路径即为由起点到终点的第k短路
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
int n,m,ts,te,k,ru,rv,rw,tot;
int first[100010],nxt[100010],cnt[100010];
bool flag;
ll ans;
struct edge
{
int u,v,w;
}l[100010];
struct st
{
int num;
ll d;
}p;
bool operator < (st a,st b)
{
return a.d>b.d;
}
priority_queue<st>q;
void build(int f,int t,int c)
{
l[++tot]=(edge){f,t,c};
nxt[tot]=first[f];
first[f]=tot;
}
void Dijkstra()
{
q.push((st){ts,0});
while(!q.empty())
{
st h=q.top();
q.pop();
if(cnt[h.num]>=k)//十分重要的剪枝
continue;
cnt[h.num]++;
if(h.num==te&&cnt[h.num]==k)
{
flag=1;
ans=h.d;
break;
}
for(int i=first[h.num];i!=-1;i=nxt[i])
{
int x=l[i].v;
q.push((st){x,h.d+l[i].w});
}
}
}
int main()
{
freopen("swim.in","r",stdin);
freopen("swim.out","w",stdout);
memset(first,-1,sizeof(first));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&ru,&rv,&rw);
build(ru,rv,rw);
}
scanf("%d%d%d",&ts,&te,&k);
tot=0;
Dijkstra();
if(flag)
printf("%I64d",ans);
else printf("-1");
fclose(stdin);
fclose(stdout);
return 0;
}
Problem 4:
注释..
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
int n,tot;
ll ans=1,mod=100000007;
ll prime[5000010],cnt[5000010];
bool vis[5000010];
ll powr(ll a,ll b)//递归版快速幂
{
if(b==0) return 1;
ll tmp=powr(a,b>>1);
tmp=tmp*tmp%mod;
if(b&1) tmp=tmp*a%mod;
return tmp%mod;
}
ll powe(ll a,ll b)//非递归版
{
ll r=1,base=a;
while(b!=0)
{
if(b&1)
r=r*base%mod;
base=base*base%mod;
b=b>>1;
}
return r%mod;
}
int main()
{
scanf("%d",&n);
vis[1]=1;
for(int i=2;i<=sqrt(n);i++)
{
if(!vis[i])
{
for(int j=i*i;j<=n;j+=i)
vis[j]=1;
}
}
for(ll i=1;i<=n;i++)
{
if(!vis[i])
prime[++tot]=i;
}
for(int i=1;i<=tot;i++)
{
ll k=n;
while(k!=0)
{
cnt[i]+=k/prime[i];//a^k<n<a^(k+1)
k/=prime[i]; //cnt[i]=a^k/a^1+a^k/a^2+...+a^k/a^k即n/a^1+n/a^2+...+n/a^k分层统计次数
}
}
for(int i=1;i<=tot;i++)
{
if(cnt[i]%2==0)
ans=(ans*powr(prime[i],cnt[i]))%mod;//次数为偶则计入答案
else
ans=(ans*powr(prime[i],cnt[i]-1))%mod;//次数为奇则减一(不选)计入答案
}
printf("%lld\n",ans);
return 0;
}
/*
思想:
唯一分解定理:任何大于1的自然数,都可以唯一分解成有限个质数的乘积
n个完全平方数相乘一定是完全平方数,为使结果最大尽量多的选取数字;
对于算法正确性,关键在于确定一个数不会部分被取,部分不被取;
偶数次幂不作处理;
对于奇数次幂的-1,可以理解为将他本身从连乘中删去;
那么删去的数都是质数,也就不存在一个数部分被取,部分不被取;
*/