ACM基础题型小集合

这个博客包含多个ACM编程题目,涉及动态规划、数据结构、搜索算法等多个方面。例如,第一道题目要求在限制背包容量的情况下,最大化苹果的总价值;第二题是一个关于不含特定子串的01串计数问题;第三题是关于公平分配西瓜的问题,目标是最小化两堆西瓜的重量差;第四题是寻找最长单调递增子序列的长度。博客通过示例代码详细解释了如何解决这些问题,适合ACM竞赛爱好者学习和练习。
测试机型:NYOJ(南阳理工大学ACM网站)
苹果
时间限制:3000 ms  |  内存限制:65535 KB 
难度:3
描述 
ctest有n个苹果,要将它放入容量为v的背包。给出第i个苹果的大小和价钱,求出能放入背包的苹果的总价钱最大值。
输入有多组测试数据,每组测试数据第一行为2个正整数,分别代表苹果的个数n和背包的容量v,n、v同时为0时结束测试,此时不输出。接下来的n行,每行2个正整数,用空格隔开,分别代表苹果的大小c和价钱w。所有输入数字的范围大于等于0,小于等于1000。输出对每组测试数据输出一个整数,代表能放入背包的苹果的总价值。样例输入3 3
1 1
2 1
3 1
0 0
样例输出2
来源动态规划经典问题
#include <cstdio>
#include <algorithm>
#include <cstring>
int c[1000],w[1000],dp[1000][1000];
using namespace std;
int main(){
int i,j;
int n,m;
while(~scanf("%d%d",&n,&m),(n||m)){
   for(i=0;i<n;i++){
    scanf("%d%d",&c[i],&w[i]);
}
memset(dp,0,sizeof(dp));
for(i=0;i<n;i++){
          for(j=0;j<=m;j++){
        if(j<c[i])  dp[i+1][j]=dp[i][j];
        else   dp[i+1][j]=max(dp[i][j],dp[i][j-c[i]]+w[i]);
          }
}
printf("%d\n",dp[n][m]);
}
return 0;
}

ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有“11”子串的这种长度的01串共有多少个,他希望你能帮帮他。

注:01串的长度为2时,有3种:00,01,10。

输入第一行有一个整数n(0<n<=100),表示有n组测试数据;
随后有n行,每行有一个整数m(2<=m<=40),表示01串的长度;输出输出不含有“11”子串的这种长度的01串共有多少个,占一行。样例输入2
2
3
样例输出
3
5
#include <stdio.h>
#define __int64 long long
int main(){
__int64 f[41] = { 0 , 0 , 3 , 5 } ;
int Total , i ;
for( i = 4 ; i < 41 ; ++i )
f[i] = f[i-1] + f[i-2] ;
scanf("%d", &Total ) ;
while( Total-- )
{scanf("%d", &i ) ;
printf("%d\n", f[i] ) ;
}
return 0 ;
}
zb的生日
时间限制:3000 ms  |  内存限制:65535 KB 
难度:2
描述 今天是阴历七月初五,acm队员zb的生日。zb正在和C小加、never在武汉集训。他想给这两位兄弟买点什么庆祝生日,经过调查,zb发现C小加和never都很喜欢吃西瓜,而且一吃就是一堆的那种,zb立刻下定决心买了一堆西瓜。当他准备把西瓜送给C小加和never的时候,遇到了一个难题,never和C小加不在一块住,只能把西瓜分成两堆给他们,为了对每个人都公平,他想让两堆的重量之差最小。每个西瓜的重量已知,你能帮帮他么?
输入多组测试数据(<=1500)。数据以EOF结尾
 第一行输入西瓜数量N (1 ≤ N ≤ 20)
第二行有N个数,W1, …, Wn (1 ≤ Wi ≤ 10000)分别代表每个西瓜的重量
输出输出分成两堆后的质量差样例输入
5
5 8 13 27 14
样例输出3
import java.util.Scanner;
import java.util.Arrays;
public class Main
{
	public static int abs(int a){
	if(a<0)return -a;
	return a;
	}
	public static int[] w=new int[21];
	public static int []dp=new int[200010];
	public static void main(String [] agrs){
		int N,i,j,record,sum;
	Scanner cin=new Scanner(System.in);
while(cin.hasNext()){
	N=cin.nextInt();
    record=0;
	 for(i=0;i<N;i++){
    w[i]=cin.nextInt();
    record+=w[i];
 }
    Arrays.fill(dp,0);
    sum=record>>1;
    for(i=0;i<N;i++){
    for(j=sum;j>=w[i];j--){
dp[j]=Math.max(dp[j],dp[j-w[i]]+w[i]);
    }
    }
	System.out.println(abs(record-(dp[sum]<<1)));
	}
}
}

单调递增子序列(二)
时间限制:1000 ms  |  内存限制:65535 KB 
难度:4
描述 
给定一整型数列{a1,a2...,an}(0<n<=100000),找出单调递增最长子序列,并求出其长度。
如:1 9 10 5 11 2 13的最长单调递增子序列是1 9 10 11 13,长度为5。
输入有多组测试数据(<=7)
 每组测试数据的第一行是一个整数n表示序列中共有n个整数,随后的下一行里有n个整数,表示数列中的所有元素.每个整形数中间用空格间隔开(0<n<=100000)。
 数据以EOF结束 。
 输入数据保证合法(全为int型整数)!输出对于每组测试数据输出整形数列的最长递增子序列的长度,每个输出占一行。样例输入7
1 9 10 5 11 2 13
2
2 -1
样例输出
5
1
来源[521521]改编
//超时代码
import java.util.Scanner;
import java.util.Arrays;
public class Main
{
	public static int [] dp=new int[100010];
	public static int [] a=new int[100010];
	public static void main(String [] agrs){
	Scanner cin=new Scanner(System.in);
    int n,m,i,j;
     while(cin.hasNext()){
      n=cin.nextInt();
      for(i=0;i<n;i++){
     a[i]=cin.nextInt();
	 dp[i]=1;
 }
for(i=0;i<n;i++){
for(j=0;j<i;j++){
if(a[j]<a[i]){
dp[i]=dp[j]+1;
}
else{
dp[i]=Math.max(dp[i],dp[j]);
}
}
}
System.out.println(dp[n-1]);
 }
		}
}
//正解
#include <cstdio>
#include <algorithm>
const int INF=10000000;
using namespace std;
int a[100010],dp[100010];
int main(){
    int n,m,i,j;
while(scanf("%d",&n)==1){
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
fill(dp,dp+n,INF);
for(i=0;i<n;i++){
    *lower_bound(dp,dp+n,a[i])=a[i];
}
printf("%d\n",lower_bound(dp,dp+n,INF)-dp);
}
return 0;
}
//
 
#include<cstdio>

#include<algorithm>

using namespace std;

const int MAX=100100;

int num[MAX],top=0;

int main()
{

int n;

while(~scanf("%d",&n))
{
	
scanf("%d",&num[0]);

top=1;

for(int i=1;i!=n;i++)
	{
	
scanf("%d",&num[i]);
	
int * p=lower_bound(num,num+top,num[i]);
if(p-num==top) ++top;

*p=num[i];
		
}
		
printf("%d\n",top);

	}

return 0;
	
}        
LJ的质数研究史(2)
Description:
在研究了一段时间后,LJ对质数产生了一种变态的爱恋,这让他看到合数就要把它分解成质数。
*标准分解式:每一个整数都可以被分解成一些质数的连乘积,我们称这一个连乘积为标准分解式。
Input:
第一行是一个正整数N(N<=100)表示测试数据的组数,接下来是N组测试数据。
每组测试数据只占一行,包括一个整数x(2<=x<=100000000)。
Output:
对每组测试数据输出一行,为x的标准分解式,格式为:x = p1^n1 * p2^n2 * p3^n3 ...(pn是质数,且有p1<p2<p3...)
Sample Input:
2
125127
56358532
Sample Output:
125127 = 3^2 * 13903^1
56358532 = 2^2 * 337^1 * 41809^1
#include <cstdio>
#include <string>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int prime[5000005],pri[500005],cnt,N;
void init(){
cnt=0;
for(int i=2;i<=5000005;i++){
    if(!prime[i]){
        pri[cnt++]=i;
        for(int j=i*2;j<=5000005;j+=i){
            prime[j]=1;
        }
    }
}
}
void setDate(int M){
    int kkk=0,record=0;
for(int i=0;i<cnt;i++){
        kkk=0;
        while(M%pri[i]==0){
           kkk++;
           M/=pri[i];
    }
    if(kkk>0){
    if(record!=0)printf(" * ");
    printf("%d^%d",pri[i],kkk);
    record++;
    }
}
if(M>1){
        if(record!=0)printf(" * ");
    printf("%d^1",M);
}
if(N!=0)
printf("\n");
}
int main(){
int M;
init();
scanf("%d",&N);
while(N--){
    scanf("%d",&M);
    printf("%d = ",M);
    setDate(M);
}
return 0;
}

C - An Easy Task
  Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u  
Submit
Status
Description
Ignatius was born in a leap year, so he want to know when he could hold his birthday party. Can you tell him? 
Given a positive integers Y which indicate the start year, and a positive integer N, your task is to tell the Nth leap year from year Y. 
Note: if year Y is a leap year, then the 1st leap year is year Y. 
Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow. 
Each test case contains two positive integers Y and N(1<=N<=10000). 
Output
For each test case, you should output the Nth leap year from year Y.
Sample Input
 3
2005 25
1855 12
2004 10000 
Sample Output
 2108
1904
43236 
#include <cstdio>
using namespace std;
int year,hol;
void  leapyear(){
	 int i=0;
	 while(true){
		 if((year%4==0&&year%100!=0)||year%400==0){
			 i++;
			 if(i==hol)break;
			 year+=4;
		 }
		 else year++;
	 }
}
int main(){
	int N;scanf("%d",&N);getchar();
	while(N--){
		scanf("%d%d",&year,&hol);
		leapyear();
		printf("%d\n",year);
	}
	return 0;

输入数据的第一行是一个整数C,表示测试实例的个数,然后是C 行数据,每行包含一个整数n(0<n<=10000),表示折线的数量。 
Output
对于每个测试实例,请输出平面的最大分割数,每个实例的输出占一行。 
Sample Input
 2
1
2 
Sample Output
 2
7 
#include <cstdio>
using namespace std;
int main(){
	int n,k;
	scanf("%d",&n);
	while(n--){
	scanf("%d",&k);
	printf("%d\n",2*k*k-k+1);
	    }
	return 0;
	}
分拆素数和
Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 22695    Accepted Submission(s): 9833
Problem Description
把一个偶数拆成两个不同素数的和,有几种拆法呢?
Input
输入包含一些正的偶数,其值不会超过10000,个数不会超过500,若遇0,则结束。
Output
对应每个偶数,输出其拆成不同素数的个数,每个结果占一行。
Sample Input
30
26
0
Sample Output
3
2
Source
 2007省赛集训队练习赛(2) 
import java.util.Scanner;
import java.math.BigInteger;
public class Main
{
	public static boolean is_prime(int x){
	int i;
	if(x==2) return true;
	for(i=2;i<=Math.sqrt(x);i++){
		if(x%i==0)return false;
	}
	return true;
}
	public static void main(String [] agrs){
	Scanner cin=new Scanner(System.in);
	int i,n,m;
	while(true){
		n=0;m=cin.nextInt();
		if(m==0) break;
		for(i=2;i<m-i;i++){
		if(is_prime(i)&&is_prime(m-i))
			n++;
		}
		System.out.println(n);
	}
	}
}
B - Rightmost Digit
  Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u  
Submit
Status
Description
Given a positive integer N, you should output the most right digit of N^N. 
Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow. 
Each test case contains a single positive integer N(1<=N<=1,000,000,000). 
Output
For each test case, you should output the rightmost digit of N^N. 
Sample Input
2
3
4 
Sample Output
 7
6 
//法1
import java.util.Scanner;
import java.math.BigInteger;
public class Main
{
public static long pow_mod(long a,long b,long c) 
{
    if(b==0) return 1;
    if(b==1) return a%c;
   long  t = pow_mod(a,b/2,c);
    if(b%2==0) 
	return (t*t)%c;
    else 
	return ((t*t)%c*a)%c;
}
	public static void main(String [] agrs){
	Scanner cin=new Scanner(System.in);
    long n,m,i;
    n=cin.nextInt();
    for(i=0;i<n;i++){
		m=cin.nextInt();
		System.out.println(pow_mod(m,m,10));
	}
	}
}
//法2
import java.util.Scanner;
import java.math.BigInteger;
public class Main
{
public static long exp_mod(long a, long  n, long b)
{
    long  t;
    if(n==0) return 1%b;
    if(n==1) return a%b;
    t=exp_mod(a,n/2,b);
    t=t*t%b;
    if((n&1)==1) t=t*a%b;
    return t;
}
	public static void main(String [] agrs){
	Scanner cin=new Scanner(System.in);
    int n,m,i;
    n=cin.nextInt();
    for(i=0;i<n;i++){
		m=cin.nextInt();
		System.out.println(exp_mod(m,m,10));
	}
	}
}
A - Leftmost Digit
  Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u 
Submit
Status
Description
Given a positive integer N, you should output the leftmost digit of N^N. 
Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow. 
Each test case contains a single positive integer N(1<=N<=1,000,000,000). 
Output
For each test case, you should output the leftmost digit of N^N. 
Sample Input
 2
3
4 
Sample Output
 2
2 

import java.util.Scanner;
public class Main
{
	public static void main(String [] agrs){
	Scanner cin=new Scanner(System.in);
    long n,m,i;
    n=cin.nextInt();
     for(i=0;i<n;i++){
		m=cin.nextInt();
		double k= Math.pow(10, m*Math.log10(m)-(long)(m*Math.log10(m)));
		System.out.println((long )k);
	}
	}
}

G - Buy the Ticket
  Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u  
Submit
Status
Description
The "Harry Potter and the Goblet of Fire" will be on show in the next few days. As a crazy fan of Harry Potter, you will go to the cinema and have the first sight, won’t you? 
Suppose the cinema only has one ticket-office and the price for per-ticket is 50 dollars. The queue for buying the tickets is consisted of m + n persons (m persons each only has the 50-dollar bill and n persons each only has the 100-dollar bill). 
Now the problem for you is to calculate the number of different ways of the queue that the buying process won't be stopped from the first person till the last person. 
Note: initially the ticket-office has no money. 
The buying process will be stopped on the occasion that the ticket-office has no 50-dollar bill but the first person of the queue only has the 100-dollar bill. 
Input
The input file contains several test cases. Each test case is made up of two integer numbers: m and n. It is terminated by m = n = 0. Otherwise, m, n <=100. 
Output
For each test case, first print the test number (counting from 1) in one line, then output the number of different ways in another line. 
Sample Input
 3 0
3 1
3 3
0 0 
import java.util.Scanner;
import java.math.BigInteger;
import java.math.BigDecimal;
public class Main {
		public static void main(String[] args)
		{
		Scanner cin=new Scanner(System.in);
		int i=0,j,m,n;
		while(cin.hasNext()){     	      
			  BigDecimal qu=new BigDecimal(1);
			  m=cin.nextInt(); n=cin.nextInt();
			  if(m==0&&n==0)break;
			  i++;System.out.println("Test #"+i+":");  
			  if(m<n)System.out.println(0);  
			  else{     			     
		    	  if(n==0){
		                for(j=1;j<=m+n;j++){
		                qu=qu.multiply(new BigDecimal(j));
						}
		        	     System.out.println(qu); 
		    	  }
		    	  else{
			                 for(j=1;j<=m+n;j++){
					 if(j!=m+1)
			 	                qu=qu.multiply(new BigDecimal(j));
			                 }
			        	     System.out.println(qu.multiply(new BigDecimal(m-n+1)));
		           }
			 }
		}
	}
}


D - 改革春风吹满地
  Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u  
Submit
Status
Description
“ 改革春风吹满地, 
不会AC没关系; 
实在不行回老家, 
还有一亩三分地。 
谢谢!(乐队奏乐)” 
话说部分学生心态极好,每天就知道游戏,这次考试如此简单的题目,也是云里雾里,而且,还竟然来这么几句打油诗。 
好呀,老师的责任就是帮你解决问题,既然想种田,那就分你一块。 
这块田位于浙江省温州市苍南县灵溪镇林家铺子村,多边形形状的一块地,原本是linle 的,现在就准备送给你了。不过,任何事情都没有那么简单,你必须首先告诉我这块地到底有多少面积,如果回答正确才能真正得到这块地。 
发愁了吧?就是要让你知道,种地也是需要AC知识的!以后还是好好练吧... 
Input
输入数据包含多个测试实例,每个测试实例占一行,每行的开始是一个整数n(3<=n<=100),它表示多边形的边数(当然也是顶点数),然后是按照逆时针顺序给出的n个顶点的坐标(x1, y1, x2, y2... xn, yn),为了简化问题,这里的所有坐标都用整数表示。 
输入数据中所有的整数都在32位整数范围内,n=0表示数据的结束,不做处理。 
Output
对于每个测试实例,请输出对应的多边形面积,结果精确到小数点后一位小数。 
每个实例的输出占一行。 
Sample Input
 3 0 0 1 0 0 1
4 1 0 0 1 -1 0 0 -1
0 
Sample Output
 0.5
2.0 
#include<stdio.h>
int main(){
	int n,i,p;
	int a[100];
	int b[100];
	double c;
	while (scanf("%d", &n), n != 0){
		i = 0; p = n; c = 0;
		while (n--)
		{scanf("%d%d", &a[i], &b[i]); i++;}
		for (i = 0; i < p - 1; i++)
		c = c + 0.5*(a[i] * b[i + 1] - a[i + 1] * b[i]);
		c = c + 0.5*(a[p-1] * b[0] - a[0] * b[p-1]);
		printf("%.1f\n", c);
	}
return 0;
}



又见01背包

时间限制:1000 ms  |  内存限制:65535 KB 

难度:3

描述 
    有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W 

的物品,求所有挑选方案中物品价值总和的最大值。

  1 <= n <=100

  1 <= wi <= 10^7

  1 <= vi <= 100

  1 <= W <= 10^9

输入多组测试数据。
 每组测试数据第一行输入,n 和 W ,接下来有n行,每行输入两个数,代表第i个物品的wi 和 vi。输出满足题意的最大价值,每组测试数据占一行。样例输入4 5
2 3
1 2
3 4
2 2
样例输出7
来源飘谊系列上传者TC_张友谊


#include <cstdio>
#include <algorithm>
#include <cstring>
const int INF=1<<30;
using namespace std;
int v[110],w[110];
int dp[110][10005];
int main(){
int n,W,record=0;
int sum;
while(~scanf("%d%d",&n,&W)){
        sum=0;
    for(int i=0;i<n;i++){
        scanf("%d%d",&w[i],&v[i]);
    sum+=v[i];
    }
    for(int i=0;i<=sum;i++){
        dp[0][i]=INF;
    }
    record=0;
    dp[0][0]=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<=sum;j++){
            if(j<v[i]){
                dp[i+1][j]=dp[i][j];
            }
            else{
                dp[i+1][j]=min(dp[i][j],dp[i][j-v[i]]+w[i]);
            }
        }
    }
    for(int i=0;i<=sum;i++){
        if(dp[n][i]<=W){
            record=i;
        }
    }
    printf("%d\n",record);
}
return 0;
}




又见拦截导弹

时间限制:3000 ms  |  内存限制:65535 KB 

难度:3

描述 
大家对拦截导弹那个题目应该比较熟悉了,我再叙述一下题意:某国为了防御敌国的导弹袭击,新研制出来一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高度。突然有一天,雷达捕捉到敌国的导弹来袭。由于该系统存在缺陷,所以如果想把所有的导弹都拦截下来,就要多准备几套这样的导弹拦截系统。但是由于该系统成本太高,所以为了降低成本,请你计算一下最少需要多少套拦截系统。

输入有多组测试数据。
 每组数据先输入一个整数N(N≤3000),代表有N发导弹来袭。接下来有N个数,分别代表依次飞来的导弹的导弹的高度。当N=-1时表示输入结束。输出每组输出数据占一行,表示最少需要多少套拦截系统。样例输入8
389 207 155 300 299 170 158 65
5
265 156 123 76 26
样例输出
2
1
#include <cstdio>
#include <algorithm>
#include <cstring>
int dp[3010],ss[3010];
using namespace std;
int  main(){
int N,i,j;
while(~scanf("%d",&N)){
if(N==-1)break;
 for(i=0;i<N;i++){
    scanf("%d",&ss[i]);
 }
 int res=0;
 for(i=0;i<N;i++){
 dp[i]=1;
 for(j=0;j<i;j++){
 if(ss[i]>ss[j])
 dp[i]=max(dp[i],dp[j]+1);
 }
 res=max(res,dp[i]);
 }
 printf("%d\n",res);
 }
return 0;
}
import java.util.Scanner;
import java.math.*;
import java.io.BufferedInputStream;
public class Main
{
	public static int [] dp=new int [3010];
	public static int [] ss=new int [3010];
	public static void main(String [] agrs){
Scanner cin=new Scanner(new BufferedInputStream(System.in));
int N,i,j;
while(cin.hasNext()){
 N=cin.nextInt();
 if(N==-1)break;
 for(i=0;i<N;i++){
    ss[i]=cin.nextInt();
 }
 int res=0;
 for(i=0;i<N;i++){
 dp[i]=1;
 for(j=0;j<i;j++){
 if(ss[i]>ss[j])
 dp[i]=Math.max(dp[i],dp[j]+1);
 }
 res=Math.max(res,dp[i]);
 }
 System.out.println(res);
}
	}
}







邮票分你一半
时间限制:1000 ms  |  内存限制:65535 KB 
难度:3
描述      小珂最近收集了些邮票,他想把其中的一些给他的好朋友小明。每张邮票上都有分值,他们想把这些邮票分成两份,并且使这两份邮票的分值和相差最小(就是小珂得到的邮票分值和与小明的差值最小),现在每张邮票的分值已经知道了,他们已经分好了,你知道最后他们得到的邮票分值和相差多少吗?
输入第一行只有一个整数m(m<=1000),表示测试数据组数。
 接下来有一个整数n(n<=1000),表示邮票的张数。
 然后有n个整数Vi(Vi<=100),表示第i张邮票的分值。输出输出差值,每组输出占一行。样例输入2
5
2 6 5 8 9
3
2 1 5
样例输出
0
2


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int INF=10000000;
int v[110],dp[100005];
int main(){
int m,n;
int recordi,recordj;
scanf("%d",&m);
while(m--){
       memset(dp,0,sizeof(dp));
        //fill(dp,dp+100000,INF);
        recordi=0;recordj=0;
    int sum=0;
    scanf("%d",&n);
  for(int i=0;i<n;i++){
    scanf("%d",&v[i]);
sum+=v[i];
  }
  int res=0;
  for(int i=0;i<n;i++){
    for(int j=sum/2;j>=v[i];j--){
        dp[j]=max(dp[j],dp[j-v[i]]+v[i]);
    }
  }
  printf("%d\n",sum-2*dp[sum/2]);
}
return 0;
}

运行结果
本题排行
讨论区




VF
时间限制:1000 ms  |  内存限制:65535 KB 
难度:2
描述 
Vasya is the beginning mathematician. He decided to make an important contribution to the science and to become famous all over the world. But how can he do that if the most interesting facts such as Pythagor’s theorem are already proved? Correct! He is to think out something his own, original. So he thought out the Theory of Vasya’s Functions. Vasya’s Functions (VF) are rather simple: the value of the Nth VF in the point S is an amount of integers from 1 to N that have the sum of digits S. You seem to be great programmers, so Vasya gave you a task to find the milliard VF value (i.e. the VF with N = 109) because Vasya himself won’t cope with the task. Can you solve the problem?
输入There are multiple test cases.
 Integer S (1 ≤ S ≤ 81).输出The milliard VF value in the point S.
样例输入
1
样例输出
10


#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
int dp[11][90];
int main(){
int s;
while(scanf("%d",&s)==1){
memset(dp,0,sizeof(dp));
int  res=0;
for(int i=1;i<=9;i++){
    dp[1][i]=1;
}
    for(int i=1;i<9;i++){
        for(int j=1;j<=9*(i+1);j++){
                for(int k=0;k<=9;k++){
                if(k>j) break;
           dp[i+1][j]+=dp[i][j-k];
        }
       }
       res+=dp[i][s];
    }
   if(s==1){
        printf("10\n");
   }
    else
    printf("%d\n",res+dp[9][s]);
}
return 0;
}
擅长排列的小明 II
时间限制:1000 ms  |  内存限制:65535 KB
难度:3
描述
小明十分聪明,而且十分擅长排列计算。
有一天小明心血来潮想考考你,他给了你一个正整数n,序列1,2,3,4,5......n满足以下情况的排列:
1、第一个数必须是1
2、相邻两个数之差不大于2
你的任务是给出排列的种数。
输入
多组数据。每组数据中输入一个正整数n(n<=55).
输出
输出种数。
样例输入
4
样例输出
4
#include <cstdio>
#include <cstring>
using namespace std;
int dp[60];
int main(){
int n;
while(~scanf("%d",&n)){
    dp[1]=1;dp[2]=1;dp[3]=2;
    for(int i=3;i<=n;i++){
      dp[i]=dp[i-1]+dp[i-3]+1;
    }
  printf("%d\n",dp[n]);
}
return 0;
}
An problem about date
时间限制:2000 ms  |  内存限制:65535 KB
难度:2
描述
acm的iphxer经常忘记某天是星期几,但是他记那天的具体日期,他希望你能写个程序帮帮他。
输入
每行有三个整数 year,month,day,日期在1600年1月1日到9600年1月1日之间;
输出
输出对应的星期,用一个整数表示;(星期一到星期六用1-6表示,星期日用0表示)
样例输入
2011 3 6
1949 10 1
2011 4 1
1945 8 15
样例输出
0
6
5
3

//法一
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int main(){
int year,day,monthes;
while(~scanf("%d%d%d",&year,&monthes,&day)){
        if(monthes<=2){
        monthes+=12;
        year--;
    }
    int record=(day+2*monthes+3*(monthes+1)/5+year+year/4-year/100+year/400+1);
    record%=7;

    printf("%d\n",record);
}
return 0;
}
//法二
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int main(){
int year,day,monthes;
while(~scanf("%d%d%d",&year,&monthes,&day)){
    if(monthes<=2){
        monthes+=12;
        year--;
    }
int pre=year/100,nex=year%100;
    int record=(nex+floor(nex/4)+floor(pre/4)-2*pre+floor(26*(monthes+1)/10)+day-1);
    record%=7;
    if(record<0){
        record+=7;
    }
    printf("%d\n",record);
}
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值