您的位置:首页 > 其它

哈尔滨理工大学2016级新生程序设计全国邀请赛

2016-12-11 18:09 399 查看
题目链接:点我点我(2293-2303)

A 棋盘村

简单dp

dp[1][1]=1

dp[i][j]=dp[i-1][j]+dp[i][j-1]

判掉强盗能到的地方即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll vis[25][25];
int main(){
ll t;
scanf("%lld",&t);
while(t--){
ll i,j,n,m,x,y;
memset(vis,0,sizeof(vis));
scanf("%lld%lld%lld%lld",&n,&m,&x,&y);
n++;
m++;
x++;
y++;
if(x-2>=0&&y-1>=0)vis[x-2][y-1]=-1;
if(x-1>=0&&y-2>=0)vis[x-1][y-2]=-1;
if(x-2>=0)vis[x-2][y+1]=-1;
if(x-1>=0)vis[x-1][y+2]=-1;
if(y-2>=0)vis[x+1][y-2]=-1;
if(y-1>=0)vis[x+2][y-1]=-1;
vis[x+2][y+1]=-1;
vis[x+1][y+2]=-1;
vis[x][y]=-1;
if(vis[1][1]!=-1){
vis[1][1]=1;
for(i=1;i<=n;i++){
for(j=1;j<=m;j++){
if(vis[i][j]==-1)continue;
if(vis[i-1][j]!=-1)vis[i][j]+=vis[i-1][j];
if(vis[i][j-1]!=-1)vis[i][j]+=vis[i][j-1];
}
}
}
printf("%lld\n",vis
[m]);
}
return 0;
}


B 修建传送门

首先左传送门肯定放在1位置  不然会多走1到左传送门的距离

所以可以利用双指针  枚举右传送门的位置  进而找出折中点  更新ans即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
ll sum[100005];
int main(){
ll t;
scanf("%lld",&t);
while(t--){
ll n,i,j,x;
scanf("%lld",&n);
memset(sum,0,sizeof(sum));
for(i=2;i<=n;i++){
scanf("%lld",&x);
sum[i]+=sum[i-1]+x;
}
ll zhe=1,ans=1;
for(i=1;i<=60;i++)ans*=2;
for(i=2;i<=n;i++){
ll d=min(ans,sum
-sum[i]);
while(zhe!=n-1&&max(sum[i]-sum[zhe+1],sum[zhe]-sum[1])>max(sum[i]-sum[zhe+2],sum[zhe+1]-sum[1]))zhe++;
d=max(sum[zhe]-sum[1],d);
d=max(sum[i]-sum[zhe+1],d);
ans=min(ans,d);
}
if(n==1)ans=0;
cout<<ans<<endl;
}
return 0;
}


C 方方正正

首先行列和不相同肯定不行

其次如果行上的最大值如果大于列的非零值的个数也不行  列同理

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int row[100005],col[100005];
int main(){
int i,j,r,c;
while(scanf("%d%d",&r,&c)!=EOF){
ll rsum=0,csum=0;
ll numr,numc,maxc,maxr;
maxr=maxc=numr=numc=0;
for(i=1;i<=r;i++){
scanf("%d",&row[i]);
rsum+=row[i];
if(row[i]>0)numr++;
if(row[i]>maxr)maxr=row[i];
}
for(i=1;i<=c;i++){
scanf("%d",&col[i]);
csum+=col[i];
if(col[i]>0)numc++;
if(col[i]>maxc)maxc=col[i];
}
int flag=1;
if(rsum!=csum)flag=0;
if(numc<maxr||numr<maxc)flag=0;
if(flag)printf("YES\n");
else printf("NO\n");
}
return 0;
}


D 陈月亮的数学题

我们知道可以将一个数N分解成N=pa11∗pa22∗pa33∗…∗pann,其中Pi为素数。这样N的因子个数为(a1+1)(a2+1)(a3+1)…(ak+1)=∏ki=1(ai+1)。 
所以N的所有因子的因子个数为∏ki=1(1+2+3+…+ai+1)=∏ki=1(1+ai+1)(ai+1)2,但这只是S=n1+n2+n3+…+nk的值。 
所以,我们可以从1+2+3+…+n=(1+n)n2。 
12+22+32+…+n2=(2+n)(1+n)n6 
13+23+33+…+n3=((1+n)n2)2中得到启示。 
所以最终S=n31+n32+n33+…+n3k的答案为∏ki=1((1+ai+1)(ai+1)2)2

膜一发神犇的题解。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int prime[100005],num[100005],cnt=0;
void init(){
for(int i=2;i<=65536;i++){
if(!prime[i])num[++cnt]=i;
for(int j=2;j*i<=65536;j++){
prime[j*i]=1;
if(!(i%j)) break;
}
}
}
int main(){
int t;
init();
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
ll ans=1;
for(int i=1;i<=cnt;i++){
if(n%num[i]==0){
int s=0;
while(n%num[i]==0){
n/=num[i];
s++;
}
ll temp=(2+s)*(1+s)*(2+s)*(1+s)/4;
ans*=temp;
}
}
if(n>1)ans*=9;
cout<<ans<<endl;
}
return 0;
}


E Nine Digits

康拓展开后bfs即可  但是这样会超时

所以可以先处理出原序列能到的地方  然后每次询问查询康拓展开

原来是顺时针  所以预处理时候用逆时针

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<deque>
using namespace std;
deque<int>sp;
int fac[] = {1,1,2,6,24,120,720,5040,40320,362880},vis[362999];
int kangtuo(int a[])  {
int i,j,t,sum;
sum=0;
for(i=0;i<9;++i)  {
t=0;
for(j=i+1;j<9;++j)
if(a[i]>a[j])sum+=fac[9-i-1];
}
return sum+1;
}
int s[20];
void reverse_kangtuo(int k){
int i,j,t,vst[9]={0};
--k;
for(i=0;i<9;i++){
t=k/fac[9-i-1];
for(j=1;j<=9;j++)
if(!vst[j]){
if(t==0)break;
--t;
}
s[i]=j;
vst[j]=1;
k%=fac[9-i-1];
}
}
int main(){
memset(vis,-1,sizeof(vis));
int m=1;
vis[1]=0;
int f;
sp.push_back(m);
while(!sp.empty()){
f=sp.front();
sp.pop_front();
reverse_kangtuo(f);
swap(s[3],s[0]);
swap(s[4],s[0]);
swap(s[1],s[0]);
m=kangtuo(s);
if(vis[m]==-1){
vis[m]=vis[f]+1;
sp.push_back(m);
}
swap(s[1],s[0]);
swap(s[4],s[0]);
swap(s[3],s[0]);
swap(s[1],s[4]);
swap(s[1],s[5]);
swap(s[1],s[2]);
m=kangtuo(s);
if(vis[m]==-1){
vis[m]=vis[f]+1;
sp.push_back(m);
}
swap(s[1],s[2]);
swap(s[1],s[5]);
swap(s[1],s[4]);
swap(s[3],s[6]);
swap(s[3],s[7]);
swap(s[3],s[4]);
m=kangtuo(s);
if(vis[m]==-1){
vis[m]=vis[f]+1;
sp.push_back(m);
}
swap(s[3],s[4]);
swap(s[3],s[7]);
swap(s[3],s[6]);
swap(s[4],s[7]);
swap(s[4],s[8]);
swap(s[4],s[5]);
m=kangtuo(s);
if(vis[m]==-1){
vis[m]=vis[f]+1;
sp.push_back(m);
}
}
while(scanf("%d%d%d%d%d%d%d%d%d",&s[0],&s[1],&s[2],&s[3],&s[4],&s[5],&s[6],&s[7],&s[8])!=EOF){
int f=kangtuo(s);
printf("%d\n",vis[f]);
}
return 0;
}


F Diamond

不会。。。

G FBI Tree

递归处理前缀和即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 1<<10
int a[maxn+5],sum[maxn+5];
void build(int l,int r){
int p=sum[r]-sum[l-1];
if(l!=r){
int len=r-l+1;
if(len%2){
build(l,(r+l)/2-1);
build((r+l)/2+1,r);
}
else{
build(l,(r+l)/2);
build((r+l)/2+1,r);
}
}
if(p==0)printf("B");
else if(p==r-l+1)printf("I");
else printf("F");
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int i,n;
scanf("%d",&n);
int len=1<<n;
for(i=1;i<=len;i++){
scanf("%1d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
build(1,len);
printf("\n");
}
return 0;
}


H 下雪啦

hash后存到vector里面  然后暴力匹配同一个集合里面的雪花

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>sp[90005];
const int mod=90001;
int snow[1000005][7];
int judge(int a,int b){
for(int i=0;i<6;i++){
if((snow[a][0]==snow[b][i]&&
snow[a][1]==snow[b][(i+1)%6]&&
snow[a][2]==snow[b][(i+2)%6]&&
snow[a][3]==snow[b][(i+3)%6]&&
snow[a][4]==snow[b][(i+4)%6]&&
snow[a][5]==snow[b][(i+5)%6])
||
(snow[a][0]==snow[b][i]&&
snow[a][1]==snow[b][(i+5)%6]&&
snow[a][2]==snow[b][(i+4)%6]&&
snow[a][3]==snow[b][(i+3)%6]&&
snow[a][4]==snow[b][(i+2)%6]&&
snow[a][5]==snow[b][(i+1)%6]))
return true;
}
return false;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,i,j,flag=0;
scanf("%d",&n);
for(i=1;i<=n;i++){
for(j=0;j<6;j++)scanf("%d",&snow[i][j]);
}
for(i=0;i<=90000;i++)sp[i].clear();
for(i=1;i<=n;i++){
int sum=0;
for(j=0;j<6;j++)sum+=snow[i][j];
sum%=mod;
for(j=0;j<sp[sum].size();j++){
if(judge(sp[sum][j],i)){
flag=1;
break;
}
}
if(flag)break;
sp[sum].push_back(i);
}
if(flag)printf("Twin snowflakes found.\n");
else printf("No two snowflakes are alike.\n");
}
return 0;
}


I 行编辑器

水题  处理个指针就行了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[1000005],ans[1000005];
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",s+1);
int d=0,i;
int len=strlen(s+1);
for(i=1;i<=len;i++){
if(s[i]=='#')d=max(0,d-1);
else if(s[i]=='@')d=0;
else ans[++d]=s[i];
}
for(i=1;i<=d;i++)printf("%c",ans[i]);
printf("\n");
}
return 0;
}


J Another Tree

建树 然后随便找个结点搜  两个点的异或距离为两个点到根节点的异或距离异或起来  根据这个性质dfs搜下去即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int head[500005],cnt,tree[1000005],k;
struct node{
int to,cap,nex;
}edge[1000005];
void add(int u,int v,int w){
edge[cnt].to=v;
edge[cnt].cap=w;
edge[cnt].nex=head[u];
head[u]=cnt++;
}
ll ans;
void dfs(int t,int d,int sum){
ans+=tree[sum^k];
tree[sum]++;
for(int i=head[d];~i;i=edge[i].nex){
int v=edge[i].to;
if(v!=t){
dfs(d,v,sum^edge[i].cap);
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(head,-1,sizeof(head));
memset(tree,0,sizeof(tree));
cnt=0;
int x,y,z,n,i;
scanf("%d%d",&n,&k);
for(i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
x++;
y++;
add(x,y,z);
add(y,x,z);
}
ans=0;
dfs(1,1,0);
printf("%lld\n",ans);
}
return 0;
}


L 小明和字符串

水题。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[55];
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%s",s+1);
int i,j,k,len=strlen(s+1);
for(i=1;i<=len;i++){
int now=0;
for(j=i+1;j<=len;j++){
if(!(s[j]>='0'&&s[j]<='9'))break;
now+=s[j]-'0';
}
for(k=1;k<=now+1;k++)printf("%c",s[i]);
i=j-1;
}
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: