1000 郭铮鹏与大学计算机基础 (模拟)
Input
只有三个整数,A,B,C。满足 0≤a≤100,0≤b≤10,0<c<100 。
Output
一个整数,即 ABmodC 。
Sample Input
2 10 7
Sample Output
2
水题,注意b可以等于0,所以最后还需要对c取模(没看数据范围,WA了)
#include <cstdio>
using namespace std;
int main() {
int a,b,c,ans;
while(3==scanf("%d%d%d",&a,&b,&c)) {
ans=1;
while(b-->0) {
ans=(ans*a)%c;
}
printf("%d\n",ans%c);
}
return 0;
}
1001 郭铮鹏与约会 (模拟)
有一天,郭铮鹏想去见一见他远在他乡的基友J,并且玩一玩他的Xbox。郭铮鹏和J都生活在笛卡尔坐标下。郭铮鹏的家在点(0,0)而J的家在点(a,b)。郭铮鹏每一次可以横向或者纵向移动一步。也就是说,他能从(x,y)移动到(x+1,y),(x-1,y),(x,y+1)或(x,y-1). 不幸的是,郭铮鹏这个人没有方向感。所以他每一步都随机选择一个方向来行走。郭铮鹏可能凑巧的走着走着又走回了他家。郭铮鹏甚至会到达基友家门口但意识不到,然后继续行走。 幸运的是,郭铮鹏成功地到达了(a,b)。到了之后他和J吹嘘:"我走了s步才走到你家呢"。但J不是很相信郭铮鹏的这句话,他不确定从(0,0)走到(a,b)走s步是否是可能的。你能帮J确定这是否可能吗?
Input
Output
对于每组数据,输出一行,如果无法走到,输出"No",否则输出"Yes"。
Sample Input
5 5 11 10 15 25 0 5 1 0 0 2
Sample Output
No Yes No Yes
水题,(0,0)到(a,b)最少要走a+b步,如果s<abs(a)+abs(b),则必定不能到达,若s>=abs(a)+abs(b),则s与a+b奇偶性相同时(即 s-abs(a)-abs(b) 为偶数),可达,否则不可达。(没看数据范围,又WA了...)
#include <cstdio>
#include <algorithm>
using namespace std;
int main() {
int a,b,s;
while(3==scanf("%d%d%d",&a,&b,&s)) {
if(s<abs(a)+abs(b)) {
printf("No\n");
}
else {
printf("%s\n",((s-abs(a)-abs(b))&1)==0?"Yes":"No");
}
}
return 0;
}
1002 郭铮鹏与杯垫 (模拟)
Input
输入由多组数据组成,每组数据一行,为三个整数k,n,w( 1≤k,w≤1000,0≤n≤109 ),分别表示第一个杯垫的售价、郭铮鹏一开始手上的钱数和他想要的杯垫数量(单位:元)。
Output
对于每组数据,输出一个整数,表示郭铮鹏至少需要借的钱,如果他不需要借钱,输出0。
Sample Input
3 17 4
Sample Output
13
这题是某次CF的A题
依旧水题,统计总共需要的钱,然后判断即可
#include <cstdio>
#include <algorithm>
using namespace std;
int main() {
int k,n,w,ans;
while(3==scanf("%d%d%d",&k,&n,&w)) {
ans=(k+w*k)*w/2-n;
printf("%d\n",ans<=0?0:ans);
}
return 0;
}
1003 郭铮鹏与比赛 (排序)
Input
Output
对于每组数据输出一行,按照输入的顺序输出每个学生的排名。每两个整数用一个空格隔开。
Sample Input
3 1 3 3 1 1 5 3 5 3 4 5
Sample Output
3 1 1 1 4 1 4 3 1
排序,然互赋予每个成绩排名即可
数据小,所以每次找最小的标记排名也可
#include <cstdio>
#include <algorithm>
using namespace std;
struct Node {
int i,a;
bool operator < (const Node& b) const {
return a>b.a;
}
}s[2005];
int n,rnk[2005];
int main() {
int cur,cnt;
while(1==scanf("%d",&n)) {
for(int i=0;i<n;++i) {
s[i].i=i;
scanf("%d",&s[i].a);
}
sort(s,s+n);
cur=1;
cnt=1;
rnk[s[0].i]=1;
for(int i=1;i<n;++i) {
if(s[i].a!=s[i-1].a) {
cur+=cnt;
cnt=0;
}
++cnt;
rnk[s[i].i]=cur;
}
printf("%d",rnk[0]);
for(int i=1;i<n;++i) {
printf(" %d",rnk[i]);
}
printf("\n");
}
return 0;
}
1004 郭铮鹏与书 (模拟)
Input
输入由多组数据组成。每组数据一行,包含一个整数n( 1≤n≤109 ),表示图书馆里书的总数。
Output
对于每组数据,输出一个整数,表示给这些书编号需要写的数字位数之和。
Sample Input
13 4
Sample Output
17 4按位数统计数字即可,得用long long,没用debug半天...
int n; long long lim[11]={0,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,1000000001}; long long ans; int main() { while(1==scanf("%d",&n)) { ans=0; for(long long i=1;i<=10&&lim[i-1]<=n;++i) { if(n>=lim[i]) { ans+=i*(lim[i]-lim[i-1]); } else { ans+=i*(n-lim[i-1]+1); } } printf("%lld\n",ans-1LL); } return 0; }
1005 GZP and Poker (数学)
Input
Output
Sample Input
4 75 150 75 50 3 100 150 250
Sample Output
Yes No
题目大意:给定n个数,每个数a[i]可以变成a[i]*(2^p)*(3^q)(p,q>=0,p,q可取任意值),问这n个数经过变换后是否能相同?
第一反应就是:设所有a[i]的最大公约数为gcd,若要变换后能相同,则a[i]/gcd的质因子只有2和3
若a[i]/gcd还存在其他质因子z,则z无法通过(2^m)*(3^n)获得,则其他数经过变换后必定不能形成与a[i]变换后想等的数
#include <cstdio>
#include <algorithm>
using namespace std;
int n,gcd,a[100005];
bool flag;
int main() {
while(1==scanf("%d",&n)) {
flag=true;
scanf("%d",a);
gcd=a[0];
for(int i=1;i<n;++i) {
scanf("%d",a+i);
gcd=__gcd(gcd,a[i]);
}
for(int i=0;i<n;++i) {
a[i]/=gcd;
while(a[i]%3==0) {
a[i]/=3;
}
while(a[i]%2==0) {
a[i]/=2;
}
if(a[i]!=1) {
flag=false;
break;
}
}
printf("%s\n",flag?"Yes":"No");
}
return 0;
}
————————————————————6题的旅游分割线————————————————————
本来不想写的,但是限于环境问题,3h就写了一道最大流,绝得效率太低,就在最后1h写了一下,发现前6题还挺简单...
估计英文第一题,才是真正的A题
1006 GZP and Counting (模拟)
Input
Output
Sample Input
3 abc 1 abcabc 1 abcabc 2
Sample Output
6 15 21题目大意:给定一个只含小写字母的字符串,统计满足限制的子串数目,子串中出现次数最多的字符出现次数不超过k。
正难则反,首先所有子串的数目很容易求出,所以只要求出不符合题意的子串就行
将每个字符每次出现的下标存入队列,当有字符出现次数超过k时,就开始减去不符合的子串,每次只计算以当前字符为结尾的不符合的子串即可,为了不漏掉不符合的,用last表示到当前字符时,存在不符合子串的起始的最靠后的下标,然后不符合的子串数就是last+1
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int k,len,cur,last;
int tail[26];
int q[26][100005];
char s[100005];
long long ans;
int main() {
int T;
scanf("%d",&T);
while(T-->0) {
scanf("%s%d",s,&k);
memset(tail,0,sizeof(tail));
ans=0;
last=-1;//last表示存在重复不符合题意的子串的最靠后的起始下标
for(len=0;s[len]!='\0';++len) {
cur=s[len]-'a';
q[cur][tail[cur]++]=len;
if(tail[cur]>k) {
last=max(last,q[cur][tail[cur]-k-1]);//更新最靠后的起始下标
}
ans-=last+1;//减去以当前字符为结尾的不符合题意的子串数
}
ans+=(1LL+len)*len/2;//最后再加上总的子串数
printf("%lld\n",ans);
}
return 0;
}
1007 GZP and world of single-dogs (计算几何)
Input
Output
Sample Input
1 1 0 1 0 1 1 0 0 0 1 1 1
Sample Output
0.4082 0.5000 0.5000 1.0000 0.6667 0.6667 0.6667一眼就看出来是高中数学解析几何,可以已经忘了...真是悲伤
找了个模版AC掉...
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const double EPS=0.000001;
typedef struct Point_3D {
double x, y, z;
Point_3D(double xx = 0, double yy = 0, double zz = 0): x(xx), y(yy), z(zz) {}
bool operator == (const Point_3D& A) const {
return x==A.x && y==A.y && z==A.z;
}
}Vector_3D;
Point_3D read_Point_3D() {
double x,y,z;
scanf("%lf%lf%lf",&x,&y,&z);
return Point_3D(x,y,z);
}
Vector_3D operator + (const Vector_3D & A, const Vector_3D & B) {
return Vector_3D(A.x + B.x, A.y + B.y, A.z + B.z);
}
Vector_3D operator - (const Point_3D & A, const Point_3D & B) {
return Vector_3D(A.x - B.x, A.y - B.y, A.z - B.z);
}
Vector_3D operator * (const Vector_3D & A, double p) {
return Vector_3D(A.x * p, A.y * p, A.z * p);
}
Vector_3D operator / (const Vector_3D & A, double p) {
return Vector_3D(A.x / p, A.y / p, A.z / p);
}
double Dot(const Vector_3D & A, const Vector_3D & B) {
return A.x * B.x + A.y * B.y + A.z * B.z;
}
double Length(const Vector_3D & A) {
return sqrt(Dot(A, A));
}
double Angle(const Vector_3D & A, const Vector_3D & B) {
return acos(Dot(A, B) / Length(A) / Length(B));
}
Vector_3D Cross(const Vector_3D & A, const Vector_3D & B) {
return Vector_3D(A.y * B.z - A.z * B.y, A.z * B.x - A.x * B.z, A.x * B.y - A.y * B.x);
}
//空间两直线上最近点对 返回最近距离 点对保存在ans1 ans2中
double SegSegDistance(Point_3D a1, Point_3D b1, Point_3D a2, Point_3D b2, Point_3D& ans1, Point_3D& ans2)
{
Vector_3D v1 = (a1 - b1), v2 = (a2 - b2);
Vector_3D N = Cross(v1, v2);
Vector_3D ab = (a1 - a2);
double ans = Dot(N, ab) / Length(N);
Point_3D p1 = a1, p2 = a2;
Vector_3D d1 = b1 - a1, d2 = b2 - a2;
double t1, t2;
t1 = Dot((Cross(p2 - p1, d2)), Cross(d1, d2));
t2 = Dot((Cross(p2 - p1, d1)), Cross(d1, d2));
double dd = Length((Cross(d1, d2)));
t1 /= dd * dd;
t2 /= dd * dd;
ans1 = (a1 + (b1 - a1) * t1);
ans2 = (a2 + (b2 - a2) * t2);
return fabs(ans);
}
int main() {
int T;
Point_3D a1,a2,b1,b2,ans1,ans2;
double dis;
scanf("%d",&T);
while(T-->0) {
a1=read_Point_3D();
a2=read_Point_3D();
b1=read_Point_3D();
b2=read_Point_3D();
dis=SegSegDistance(a1,a2,b1,b2,ans1,ans2);
printf("%.4lf\n",dis);
printf("%.4lf %.4lf %.4lf %.4lf %.4lf %.4lf\n",ans1.x,ans1.y,ans1.z,ans2.x,ans2.y,ans2.z);
}
return 0;
}
1008 GZP and CS (数位DP)
Input
Output
Sample Input
3 1 100 500
Sample Output
0 1 5
Hint
From 1 to 500, the numbers that include the sub-sequence "96" are "96","196","296","396","496",so the answer is 5.
一道裸的数位DP
官方标程错了,我写的一直WA,看了一个AC的代码,很明显发现有错...
#include <cstdio>
using namespace std;
int num[25],len;
long long n,ans;
long long dp[25][3];//dp[i][0]表示长度为i,且不含96的数字个数;dp[i][1]表示长度为i,不含96且最高位为6的数字个数;dp[i][2]表示长度为i,且含有96的数字个数
void Init() {
dp[0][0]=1;
dp[0][1]=dp[0][2]=0;
for(int i=1;i<=20;++i) {
dp[i][0]=dp[i-1][0]*10-dp[i-1][1];//长度为i-1且不含96的数字,最高位可加上0~9;但若最高位加上9,而次高位为6则不满足,所以要减去
dp[i][1]=dp[i-1][0];//长度为i-1,不含96的数字,最高位可加上9
dp[i][2]=dp[i-1][2]*10+dp[i-1][1];//长度为i-1且含96的数字,最高位可加上0~9;长度为i-1,不含96且最高位为6,则目前最高位可加上9
}
}
long long getCnt(long long x) {//返回[1,x]中含有49的数字个数
++x;
ans=len=0;
while(x>0) {
num[++len]=x%10;
x/=10;
}
num[len+1]=-1;
bool flag=false;//表示高位是否出现过96,true表示出现过
for(int i=len;i>=1;--i) {//从最高位开始枚举
ans+=dp[i-1][2]*num[i];//低i-1位中出现96的数字,当前位可取0~(num[i]-1)
if(flag) {//如果高位出现过96
ans+=dp[i-1][0]*num[i];//高位出现过96,低i-1位没有出现过96,当前位可取0~(num[i]-1)
}
if(!flag&&num[i+1]==9&&num[i]>6) {
ans+=dp[i-1][0];//高位未出现过96,且上一位为9,当前位大于6,则当前位可以取6,则低i-1为可任取不含96的数字
}
if(num[i+1]==9&&num[i]==6) {//若该位与上一位能组成96
flag=true;
}
}
return ans;
}
int main() {
Init();
int T;
scanf("%d",&T);
while(T-->0) {
scanf("%lld",&n);
printf("%lld\n",getCnt(n));
}
return 0;
}
1009 GZP and Date II (贪心&&Lucas定理)
Input
Output
Sample Input
2 1 2 2 3
Sample Output
6 18题目大意:定义在到达(x,y)的花费为c(x,y)
1. if x = 0 or y = 0, c(x,y) = 1
2. if x > 0 and y > 0, c(x,y) = c(x,y-1) + c(x-1,y)
3. if x < 0 or y < 0 c(x,y) = infinite.
每次只能向相邻的一个格子走,求从(0,0)走到(n,m)的最小花费?
大致思路:先手动写上小数据的各个格子的花费,可以看出做左上角开始的副对角线是二项式系数(杨辉三角)
又可以发现,要想花费最少,则必定只走n+m步,可以先贪心地走到(0,m)【n<=m时】 或 (n,0)【n>m时】
则转换为计算组合数了
不妨设n<=m
则答案为:m+1+C(m,1)+C(m+1,2)+…+C(m+n+1,n)=m+C(m,0)+C(m,1)+C(m+1,2)+…+C(m+n,n-1)
利用组合数性质: C(n,m)= C(n,n-m)= C(n-1,m-1)+C(n-1,m)
可得:m+C(m+n+1,n)
随便找了个模版,效率好低,跑了450ms,别人都是50ms...
换了这个模版后,瞬间变成16ms,看来模版的效率不容忽视
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
LL n,m;
LL quick_pow(LL a, LL b) {
LL ans = 1;
a %= MOD;//防止指数为0时,返回未取模的结果
while(b!=0) {
if((b & 1)==1) {
ans = ans * a % MOD;
}
b >>= 1;
a = a * a % MOD;
}
return ans;
}
LL C(LL n, LL m) {
if(n < m) {
return 0;
}
if(n == m) {
return 1;
}
if(m > n - m) {//利用组合数性质,减少运算次数
m=n - m;
}
LL ans, a = 1, b = 1;
for(int i=0; i<m; ++i) {
a = (a * (n - i)) % MOD;
b = (b * (m - i)) % MOD;
}
ans = (a * quick_pow(b, MOD-2)) % MOD;
return ans;
}
LL Lucas(LL n, LL m) {
LL ans=1;
while(m>0) {
ans=(ans*C(n % MOD, m % MOD)) % MOD;
n/=MOD;
m/=MOD;
}
return ans;
}
int main() {
int T;
scanf("%d",&T);
while(T-->0) {
scanf("%lld%lld",&n,&m);
if(n>m) {
swap(n,m);
}
printf("%lld\n",(Lucas(m+n+1,n)+m)%MOD);
}
return 0;
}