手机短号:
水题不解释了:
代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--){
char str[1000]={0};
scanf("%s",str);
printf("6%s\n",str+6);
}
return 0;
}
找单词:
提供两种做法:
第一种:母函数。
第二种:动态规划。
第一种:母函数
具体可以参考:https://www.cnblogs.com/shentr/p/5347659.html
用到的正是普通母函数,其实说句老实话,母函数说起来非常吓人,
其实这个题就是用了点皮毛,具体还是需要自个写实现乘法组合问题。
G(x)=(1+x+x^2+...+x^a1 )* ( 1+x^2+x^4+..+x^(a2*2) +...+(1+X^26+...X^(26*a26));
三个for循环,我们需要把它展开即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--){
int x=1;
int a[60]={0},b[60]={0};
a[0]=1;
for(int i=1;i<=26;i++){
scanf("%d",&x);
for(int j=0;j<=50;j++){
for(int k=0;k<=x&&j+i*k<=50;k++){
b[j+i*k]=b[j+i*k]+a[j];
}
}
for(int j=0;j<=50;j++){
a[j]=b[j];
b[j]=0;
}
}
long long ans=0;
for(int i=1;i<=50;i++){
ans+=a[i];
}
printf("%lld\n",ans);
}
return 0;
}
第二种:dp[][]
往下延伸类似于 完全背包,但是多个完全背包,所以叫多重背包。
这个题目真的很意思。
今天看了一天真的不亏。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--){
int dp[60][60]={0},x;
dp[0][0]=1;
for(int i=1;i<=26;i++){
scanf("%d",&x);
for(int j=0;j<=50;j++){
for(int k=0;k<=x&&j>=i*k;k++){
dp[i][j]+=dp[i-1][j-i*k];
}
}
}
long long ans=0;
for(int i=1;i<=50;i++){
ans+=dp[26][i];
}
printf("%lld\n",ans);
}
}
C - 简易版之最短距离
简单易懂:枚举从起点到终点每一个位置到所有位置之和。每个for循环
复杂度(500*N)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
scanf("%d",&T);
while(T--){
int a[5005];
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
}
sort(a,a+n);
int minz=0x3f3f3f3f;
for(int i=a[0];i<=a[n-1];i++){
int t=0;
for(int j=0;j<n;j++){
t+=abs(i-a[j]);
}
minz=min(minz,t);
}
cout<<minz<<endl;
}
return 0;
}
D - 数塔
有趣:这个题是我人生中的第一个DP题。
想法:
如果最下面的一层是最优的不会影响上面的抉择,
并且少了一层,那么问题就一步一步分解了。
我们每一层从下往上做到最优即可实现。
dp[i][j]+=max(dp[i+1][j],dp[i+1][j+1]);
#include<bits/stdc++.h>
using namespace std;
int main()
{
int T;
cin>>T;
while(T--){
int n,a[105][105]={0},dp[105][105]={0};
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<=i;j++){
scanf("%d",&a[i][j]);
}
}
for(int i=n-2;i>=0;i--){
for(int j=0;j<=i;j++){
a[i][j]=a[i][j]+max(a[i+1][j],a[i+1][j+1]);
}
}
printf("%d\n",a[0][0]);
}
return 0;
}
E - 核反应堆
变种的斐波纳契数列:
G[i]=3*G[i-1]+2*D[i-1]; D[i]=G[i]+D[i];
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int n;
ll G[35],D[35];
G[0]=1,D[0]=0;
for(int i=1;i<=33;i++){
G[i]=G[i-1]*3+D[i-1]*2;
D[i]=G[i-1]+D[i-1];
}
while(~scanf("%d",&n),(n!=-1)){
printf("%lld, %lld\n",G[n],D[n]);
}
return 0;
}
F - A1 = ?
推公式即可
比较难想到,但是认真观察就足以。
例如n=5;
A1=(A0+A2)/2-C1;
A2=(A1+A3)/2-C2;
A3=(A2+A4)/2-C3;
A4=(A3+A5)/2-C4;
通过上面4个式子相加得:
(A1+A4)/2=(A0+A5)-(C1+C2+C3+C4)
以这个结论以此推出:
(A1+A4)/2=(A0+A5)-(C1+C2+C3+C4)
(A1+A3)/2=(A0+A4)-(C1+C2+C3)
(A1+A2)/2=(A0+A3)-(C1+C2)
(A1+A1)/2=(A0+A2)-(C1)
再来一遍累加:
5×A1/2=4×A0/2+A5/2-(4C1+3C2+2C3+C4)
推广到一般形式:
(N+1)A1/2=N×A0/2+A5/2-(N×C1+(N-1)×C2+......+Cn)
两边乘以2:
(N+1)A1=N×A0+A5- 2×(N×C1 + (N-1)×C2+......+Cn )
答案:
A1=[ N×A0+A5- 2×(N×C1 + (N-1)×C2+......+Cn ) ] / ( N+1 )
贴上代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
double aN,a0,T,C[3005];
while(~scanf("%d",&n)){
cin>>a0>>aN;
T=0;
for(int i=n;i>=1;i--){
cin>>C[i];
T+=(i)*C[i];
}
double a1;
a1=(n*a0+aN-2*T)/(n+1);
printf("%.2lf\n",a1);
}
return 0;
}
G - 剪花布条
考点:
1、输入 cin.getline(a,sizeof(a),'\n')+sscanf(str,"%s %s",s1,s2)
2、匹配(BF算法)一一匹配即可,两个For循环头脑要清晰。
#include<bits/stdc++.h>
using namespace std;
int main()
{
char s[100005];
char s1[100005],s2[100005];
while(cin.getline(s,sizeof(s),'\n')){ //C++流输入getline
//while(scanf("%s",s1),(s1[0]=='#'&&strlen(s1)==1)?0:scanf("%s",s2))//普遍输入
int n=strlen(s);
if(s[0]=='#'&&n==1) return 0;
sscanf(s,"%s %s",s1,s2);
int n1=strlen(s1),n2=strlen(s2);
//cout<<s1<<" "<<s2<<endl;
int i,j,cnt=0;
for(i=0;i<n1;i++){
if(s1[i]==s2[0]){
for(j=0;j<n2;j++){
if(s1[i+j]!=s2[j])
break;
}
if(j==n2){
i+=(n2-1);
cnt++;
}
}
}
printf("%d\n",cnt);
}
return 0;
}
H - Box of Bricks
题解:
求出平均数和前缀和,如果每份多出来的地方累加,累加的结果就是答案。
解释:
因为需要得到平均值,必须拿走多余的地方,只考虑多的或者只考虑少的部分即可。
因为多的部分肯定会补到少的地方去。
所以这个得到的答案就是正解。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n),n){
static int b=0;
int a[10005],sum[10005]={0},aver;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=a[i]+sum[i-1];
}
aver=sum[n]/n;
int ans=0;
for(int i=1;i<=n;i++){
if(a[i]>aver){ //if(aver>a[i])
ans+=(a[i]-aver); //ans+=(aver-a[i])
}
}
if(b){
cout<<endl;
}else b++;
cout<<ans<<endl;
}
return 0;
}
I - 不要62:
题解:
这个题有多种方法,正解应该是数位DP(dfs,求不合法,只求合法)和暴力。
我先贴上代码,如果想看解释可以在我的博客里找一找。
正面求:
#include<bits/stdc++.h>
using namespace std;
int dp[10][10],d[10];
void init(){
dp[0][0]=1;
for(int i=1;i<7;i++){
for(int j=0;j<=9;j++){
for(int k=0;k<=9;k++){
if((j!=4)&&!(j==6&&k==2)){
dp[i][j]+=dp[i-1][k];
}
}
}
}
}
int S(int x){
int len=0;
int ans=0;
while(x){
d[++len]=x%10;
x/=10;
}
d[len+1]=0;
for(int i=len;i>=1;i--){
for(int j=0;j<d[i];j++){
if(j!=4&&!(d[i+1]==6&&j==2)){
ans+=dp[i][j];
}
}
if(d[i]==4||(d[i+1]==6&&d[i]==2)){
break;
}
}
return ans;
}
int main()
{
init();
int n,m;
while(~scanf("%d%d",&n,&m),(n||m)){
int ans=S(m+1)-S(n);
printf("%d\n",ans);
}
return 0;
}
反面求:
#include<bits/stdc++.h>
using namespace std;
int dp[10][3]={0},d[10]={0};
void init(){
dp[0][0]=1;
for(int i=1;i<=8;i++){
dp[i][0]=dp[i-1][0]*9-dp[i-1][1];
dp[i][1]=dp[i-1][0];
dp[i][2]=dp[i-1][2]*10+dp[i-1][1]+dp[i-1][0];
}
}
int S(int x){
int T=x,len=0;
int flag=0;
int cnt=0;
for(;x;d[++len]=x%10,x/=10);
d[len+1]=0;
for(int i=len;i>0;i--){
cnt +=( dp[i-1][2] * d[i] );
if(flag){
cnt += (dp[i-1][0]*d[i]);
}else{
if(d[i]>4) cnt+=dp[i-1][0];
if(d[i]>6) cnt+=dp[i-1][1];
if(d[i+1]==6&&d[i]>2) cnt+=dp[i][1];
}
if(d[i]==4||(d[i+1]==6&&d[i]==2)){
flag=1;
}
}
return T-cnt;
}
int main()
{
init();
int n,m;
while(~scanf("%d%d",&n,&m),(n||m)){
int ans = S(m+1)-S(n);
printf("%d\n",ans);
}
return 0;
}
正儿八经的数位DP:
#include<bits/stdc++.h>
using namespace std;
int a[10];
int dp[20][2];
int dfs(int pos,int pre,int sta,int limit){
if(pos==-1) return 1;
if(!limit&&dp[pos][sta]!=-1) return dp[pos][sta];
int up=(limit?a[pos]:9);
int tmp=0;
for(int i=0;i<=up;i++){
if( pre==6 && i==2) continue;
if(i==4) continue;
tmp+=dfs(pos-1,i,i==6,limit&&i==a[pos]);
}
if(!limit)
dp[pos][sta]=tmp;
return tmp;
}
int solve(int x){
int pos=0;
while(x){
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,-1,1,true);
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m),(n||m)){
memset(dp,-1,sizeof(dp));
printf("%d\n",solve(m)-solve(n-1));
}
return 0;
}
J - 算菜价:
题解:
这个题目考查了一样东西,就是某一位进行四舍五入。
格式:(int)(s×10+0.5) / 10.0
思考一下为什么这样???因为只要是0.5的话就会进一,如果没有就会向下取整而得到四舍的效果。
#include<bits/stdc++.h>
using namespace std;
int main()
{
char name[100];
double n,m;
double ans=0;
while(~scanf("%s%lf%lf",name,&n,&m)){
ans+=(n*m);
}
int T=(int)(ans*10+0.5);
ans=T/10.0;
printf("%.1lf\n",ans);
return 0;
}
K - 空心三角形
题解:
考查一下你输入格式,还有用草稿纸写一写规律即可。
#include<bits/stdc++.h>
using namespace std;
int main()
{
char s[3],ch;
int n;
static int m=0;
while(~scanf("%s",s),(s[0]=='@'?0:scanf("%d",&n))){
ch=s[0];
char a[100][100]={0};
for(int i=0;i<n-1;i++){
for(int j=0;j<=(n-1)*2;j++){
if(i+j==n-1){
a[i][j]=ch;
}
else if(j-i==n-1){
a[i][j]=ch;
a[i][j+1]='\0';
break;
}
else{
a[i][j]=' ';
}
if(i==0&&j==n){
a[i][j]='\0';
}
}
}
if(m) printf("\n");
else m++;
for(int i=0;i<2*n-1;i++){
a[n-1][i]=ch;
}a[n-1][2*n-1]='\0';
for(int i=0;i<n;i++){
printf("%s\n",a[i]);
}
}
return 0;
}
L - 整数解 :
题解:
因为a,b的值比较小,可以通过枚举的方法来处理问题。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll a,b;
while(~scanf("%lld%lld",&a,&b),(a||b)){
int flag=0;
for(int i=1;i<=abs(b);i++){
if(abs(b)%i==0){
if(b/i+i==a||b/(-i)-i==a){
flag=1;break;
}
}
}
flag?puts("Yes"):puts("No");
}
return 0;
}
M - 考试排名
这个题。。。。我光学了C语言是就搞不懂
现在学了C++,真的好简单呀,就是处理的问题多了点罢了。
#include<bits/stdc++.h>
using namespace std;
typedef struct P{
int Time,solved;
char name[100];
P (char nm[]=" ",int T=0,int S=0):Time(T),solved(S){
strcpy(name,nm);
}
friend bool operator <(const P & a,const P & b);
}P;
bool operator <(const P & a,const P & b){
string A=a.name,B=b.name;
if(a.Time==b.Time && a.solved==b.solved){
return A<B;
}
if(a.solved==b.solved){
return a.Time<b.Time;
}
return a.solved>b.solved;
}
P a[10000];
int main()
{
char name[1000];
int n,Ftime;
int cnt=0;
scanf("%d%d",&n,&Ftime);
while(scanf("%s",name)!=EOF){
char Problem[1000][100];
strcpy(a[cnt].name,name);
for(int i=0;i<n;i++){
scanf("%s",Problem[i]);
if(Problem[i][0]=='-'||Problem[i][0]=='0'){continue;}
else{
int T=0,C=0,flag=0;
for(int j=0;j<strlen(Problem[i]);j++){
if(Problem[i][j]=='(')flag=1;
}
if(flag){
sscanf(Problem[i],"%d(%d)",&T,&C);
a[cnt].solved++;
a[cnt].Time+=(T+C*Ftime);
}else{
sscanf(Problem[i],"%d",&T);
a[cnt].solved++;
a[cnt].Time+=(T);
}
}
}
cnt++;
}
sort(a,a+cnt);
for(int i=0;i<cnt;i++)
printf("%-10s%3d%5d\n",a[i].name,a[i].solved,a[i].Time);
return 0;
}
/*
Josephus 5 376
John 4 284
Alice 4 352
Smith 3 167
Bob 2 325
Bush 0 0
Josephus 5 376
John 4 284
Alice 4 352
Smith 3 167
Bob 2 325
Bush 0 0
*/
N_产生冠军
题解:
通过观察可以知道,冠军不能出现在输的一方,而且冠军只有一个,所以总人数-输的人数==1就说明有冠军。
用set来维护一下就可以了。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n),n){
string a[1005],b[1005];
set<string>S1;
set<string>S2;
for(int i=0;i<n;i++){
cin>>a[i]>>b[i];
S1.insert(a[i]);
S1.insert(b[i]);
S2.insert(b[i]);
}
int sum=0;
if(S1.size()-S2.size()==1){
puts("Yes");
}else{
puts("No");
}
}
return 0;
}
O - find your present (2)
题解:
利用异或来实现奇偶性问题。只要是出现的奇数性肯定会只有一个。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(~scanf("%d",&n),n){
int ans=0,x;
scanf("%d",&ans);
for(int i=0;i<n-1;i++){
scanf("%d",&x);
ans^=x;
}
printf("%d\n",ans);
}
return 0;
}
P - 小明A+B
同余模定理:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin>>n;
while(n--){
int A,B;
scanf("%d%d",&A,&B);
int ans=(A%100+B%100)%100;
cout<<ans<<endl;
}
return 0;
}
Q - Sky数
题解:
用函数实现进制的转化即可。
#include<bits/stdc++.h>
using namespace std;
int ten_16(int x){
int a[1000];
int len=0,ans=0;
while(x){
ans+=(x%16);
x/=16;
}
return ans;
}
int ten_12(int x){
int a[1000];
int len=0,ans=0;
while(x){
ans+=(x%12);
x/=12;
}
return ans;
}
int ten_10(int x){
int a[1000];
int len=0,ans=0;
while(x){
ans+=(x%10);
x/=10;
}
return ans;
}
int main()
{
int n;
while(~scanf("%d",&n),n){
if(ten_10(n)==ten_12(n)&&ten_10(n)==ten_16(n)){
printf("%d is a Sky Number.\n",n);
}else{
printf("%d is not a Sky Number.\n",n);
}
}
return 0;
}
R - 分拆素数和
打一个线性素数表即可。
#include<bits/stdc++.h>
using namespace std;
int prime[10005],x[100005],cnt=0;
const int N=100005;
void is_prime(){
int t=0;
for(int i=2;i<=N;i++){
if(x[i]==0){
prime[t++]=i;
x[i]=1;
for(int j=i+i;j<=N;j+=i){
x[j]=2;
}
}
}
cnt=t;
}
int main()
{
int n;
is_prime();
//cout<<cnt<<endl;
while(~scanf("%d",&n),n){
int ans=0;
for(int i=0;prime[i]<=n;i++){
if(x[n-prime[i]]==1){
ans++;
}
}
printf("%d\n",ans/2);
}
return 0;
}
S - 整除的尾数
暴力枚举即可
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a,b;
while(~scanf("%d%d",&a,&b),(a||b)){
int cnt=0;
int ans[1000]={0};
for(int i=0;i<100;i++){
int T=a*100+i;
if(T%b==0){
ans[cnt++]=i;
}
}
for(int i=0;i<cnt;i++){
printf("%02d%c",ans[i],i==cnt-1?'\n':' ');
}
}
return 0;
}