“山大地纬杯”第十二届山东省ICPC大学生程序设计竞赛 AHK
Posted karshey
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了“山大地纬杯”第十二届山东省ICPC大学生程序设计竞赛 AHK相关的知识,希望对你有一定的参考价值。
A-Seventeen-构造
输入:
10
输出:
1+2+3+4+5+6+7+8-9-10
说明:
The following expression are considered right, too.
-10+1+2+3+4+5+6+7+8-9
((-10+1))+2+3+4+5+6+7+8-9
(-10+1)+2+3+4+5+6+7+8-9
题意:给出n,则1-n这n个数如何通过+、-、*、()得到17?
思路:
构造题。
对所有n>=17都能得到17——17+0,其中0很好凑。
对于所有9<=n<17都能得到17——(8+9)+0,其中0也很好凑。
剩下1-7的数枚举一下即可,1-3无法得出17,4-7可以得到17.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fir(i,a,n) for(int i=a;i<=n;i++)
const int N=1e5+10;
int n;
int main()
cin>>n;
if(n>=17)
cout<<"17+(1+2-3)*";
cout<<"(";
int f=0;
fir(i,4,16)
if(f) cout<<"+";
cout<<i;f++;
fir(i,18,n)
cout<<"+";
cout<<i;f++;
cout<<")";
else
if(n>=9)
//8+9
//1+2-3
cout<<"(8+9)+(1+2-3)*(";
int f=0;
fir(i,4,7)
if(f) cout<<"+";
cout<<i;f++;
fir(i,10,n)
cout<<"+"<<i;
cout<<")";
else
//<9
if(n<=3) cout<<-1;
else if(n==4) cout<<"3*(1+4)+2";
else if(n==5) cout<<"2*4+1+3+5";
else if(n==6) cout<<"(4*6-2*5+3)*1";
else if(n==7) cout<<"6*7-4*5-2-1*3";
else if(n==8) cout<<"7*8-5*6-4-2*3+1";
cout<<endl;
return 0;
H-Counting-模拟+哈希
输入:
2 2 2 1
1 1
2 2
R
U
输出:
0
1
题意:大小nxm的地图,给出k和t,k是人数,t是时间。
前k行表示第Ki个人的起始位置,后k行给出长度为t的字符串,表示第t时刻此人的走法。有上下左右四个方向。
输出t+1行,表示第Ti秒时有多少对人的编号(i,j)在同一个位置。(i<j)
思路:
模拟题。
坑点是如何存点。显然这里要存的是一对pair<int,int>
,用map会TLE,所以要用unordered_map
。
这里我们可以手动哈希——已知(x,y),且x,y的范围都小于3000,则我们可以令z=10000*x+y
,则每一个不同的点会映射到不同的z,这样就可以用不同的z来表示不同的位置,可以用unordered_map<int,int>
来存了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fir(i,a,n) for(int i=a;i<=n;i++)
const int N=3000+10;
int n,m,k,t;
int x[N],y[N];//第n个人的位置
string str[N];
int main()
cin>>n>>m>>k>>t;
fir(i,1,k) scanf("%d%d",&x[i],&y[i]);//初始位置
fir(i,1,k) cin>>str[i];
fir(i,0,t)
if(i)
for(int j=1;j<=k;j++)
char ch=str[j][i-1];
//g[x[j]][y[j]]--;
if(ch=='L') y[j]--;
else if(ch=='R') y[j]++;
else if(ch=='U') x[j]--;
else x[j]++;
unordered_map<int,int>mp;
for(int j=1;j<=k;++j) mp[x[j]*10000+y[j]]++;
int temp=0;
for(auto u:mp) temp+=(u.second)*(u.second-1)/2;
cout<<temp<<endl;
return 0;
所以n,m没有任何作用,因为题目保证数据合法…
K-Coins-枚举 或 打表+找规律
输入:
4
0
1
2
3
输出:
both
-1
A
A
题意:
A有四种硬币:2、3、17、19
B有四种硬币:5,7,11,13
有q次询问,每次输入x,问A和B是否能通过硬币组成x?若都能且使用硬币的最小个数都相等,则输出both,若都不能,则输出-1,否则:若A能则输出A,若B能则输出B。
思路1:
很明显的枚举思路
代码来自:这里
#include<bits/stdc++.h>
using namespace std;
int q,x;
int main()
scanf("%d", &q);
while(q--)
scanf("%d",&x);
if(x==0) puts("both");
else
int ans1=0,ans2=0;
int flag=0;
for(int i=x/19; i>=0; i--)
for(int j=(x-i*19)/17; j>=0; j--)
for(int k=(x-j*17-i*19)/3; k>=0; k--)
if((x-k*3-j*17-i*19)%2==0)
flag=1;
ans1=i+j+k+(x-k*3-j*17-i*19)/2;
break;
if(flag) break;
if(flag) break;
flag=0;
for(int i=x/13; i>=0; i--)
for(int j=(x-i*13)/11; j>=0; j--)
for(int k=(x-j*11-i*13)/7; k>=0; k--)
if((x-k*7-j*11-i*13)%5==0)
flag=1;
ans2=i+j+k+(x-k*7-j*11-i*13)/5;
break;
if(flag) break;
if(flag) break;
if(ans1==0&&ans2==0) puts("-1");
else if(ans1==0&&ans2!=0) puts("B");
else if(ans1!=0&&ans2==0) puts("A");
else if(ans1==ans2) puts("both");
else if(ans1>ans2) puts("B");
else puts("A");
return 0;
思路2:
这道题显然有规律。因为每次循环里的x范围都是1e9,,且A的硬币17、19很大,2、3很小,是很巧妙的数据,则这里大概率存在O(1)的解,即要——打表找规律。
很显然,本题题意:存在使硬币之和为x且硬币数量最小的值,我们可以把它看作完全背包问题,dp[i][j]表示拿了前i种硬币,背包容量刚好为j的最小代价,其中每一种硬币代价都是1,则可以开始打表:
打表代码(只打前1000个):
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fir(i,a,n) for(int i=a;i<=n;i++)
const int N=1e3+10;
int dp[N][N],dpp[N][N];//A B
int w[4],v[4],ww[4],vv[4];//A B
int main()
//A
w[1]=2,w[2]=3,w[3]=17,w[4]=19;
v[1]=1,v[2]=1,v[3]=1,v[4]=1;
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;
for(int i=1;i<=4;i++)
for(int j=0;j<=1000;j++)
dp[i][j]=dp[i-1][j];
if(j>=w[i])dp[i][j]=min(dp[i][j],dp[i][j-w[i]]+v[i]);
//B
ww[1]=5,ww[2]=7,ww[3]=11,ww[4]=13;
vv[1]=1,vv[2]=1,vv[3]=1,vv[4]=1;
memset(dpp,0x3f,sizeof(dpp));
dpp[0][0]=0;
for(int i=1;i<=4;i++)
for(int j=0;j<=1000;j++)
dpp[i][j]=dpp[i-1][j];
if(j>=ww[i])dpp[i][j]=min(dpp[i][j],dpp[i][j-ww[i]]+vv[i]);
//对比
for(int i=0;i<=1000;i++)
if(dpp[4][i]==0x3f3f3f3f&&dp[4][i]==0x3f3f3f3f) cout<<"-1";
else
if(dp[4][i]==0x3f3f3f3f) cout<<"B";
else if(dpp[4][i]==0x3f3f3f3f) cout<<"A";
else
if(dp[4][i]<dpp[4][i]) cout<<"A";
else if(dp[4][i]>dpp[4][i]) cout<<"B";
else cout<<"both";
cout<<endl;
return 0;
输出答案很容易发现——100以后的所有答案都是A。则我们可以把答案直接存下来,x>=100时直接输出A,否则读取我们存的答案,
则有代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define fir(i,a,n) for(int i=a;i<=n;i++)
const int N=1e5+10;
//-1
//A 1
//B 2
//both 0
int n;
int ans[101]=0,-1,1,1,1,2,1,2,1,1,2,2,2,2,2,2,2,1,2,1,0,1,0,0,2,0,2,2,0,2,2,2,2,2,1,2,1,0,1,0,1,1,以上是关于“山大地纬杯”第十二届山东省ICPC大学生程序设计竞赛 AHK的主要内容,如果未能解决你的问题,请参考以下文章
湖南省第十二届大学生计算机程序设计竞赛 G Parenthesis