分类: OI路程

  • 金明的预算方案 解题报告

    这题刚拿到手,不知道怎么做,后来看到了题目里说每个主件最多有0,1,2个附件,那也就是说对于每个主件及其附件而言,最多有如下几种情况:不买一件;只买主件;买主件及附件1;买主件及附件2;买主件及附件1,2都买。
    这么就好DP了,代码如下:

    C语言:

    #include <stdio.h>
    #define max(a, b) ((a)>(b)?(a):(b))
    int f[32001];
    int v[61], p[61];
    int lenth[61];
    int have[61][2];
    char not[61];
    
    int main(void)
    {
     int i, j, k;
     int n, m;
     int a, b, c;
     scanf(%d%d, &n, &m);
     for(i = 1; i <= m; i++){
     scanf(%d%d%d, &a, &b, &c);
     v[i] = a;
     p[i] = a * b;
     if(c != 0){
     have[c][lenth[c]++] = i;
     not[i] = 1;
     }
     }
     for(i = 1; i <= m; i++){
     if(not[i]){
     continue;
     }
     for(j = n; j >= v[i]; j -= 10){
    /* if(f[j] > f[j - v[i]] + p[i]){
     //这里必须不能是小于等于
     continue;
     }*/
     f[j] = max(f[j], f[j - v[i]] + p[i]);
     for(k = 0; k < lenth[i]; k++){
     if((j - v[have[i][k]] - v[i]) >= 0){
     //必须要是大于等于0 
     f[j] = max(f[j],
     f[j - v[have[i][k]] - v[i]] + p[i]
     + p[have[i][k]]);
     }
     }
     if((lenth[i] == 2) && ((j - v[i] - v[have[i][0]] - v[have[i][1]]) >= 0)){
     //必须要是大于等于0
     f[j] = max(f[j], f[j - v[i] - v[have[i][0]] - v[have[i][1]]] + p[i] + p[have[i][0]] + p[have[i][1]]);
     }
     }
     }
     printf(%d\\n, f[n]);
     return 0;
    }
  • 陶陶摘苹果 解题报告

    这种题目我确实不想写解题报告,没什么好写的,说它是贪心都不算,就是简单的模拟下。代码如下:

    C语言:

    #include <stdio.h>
    int apples[10];
    
    int main(void)
    {
     int ans;
     int i, h;
     for(i = 0; i < 10; i++){
     scanf(%d, &apples[i]);
     }
     scanf(%d, &h);
     h += 30;
     for(i = ans = 0; i < 10; i++){
     if(apples[i] <= h){
     ans++;
     }
     }
     printf(%d\\n, ans);
     return 0;
    }
  • 采药 解题报告

    就是一个经典的01背包,能够把时间看做体积,价值嘛就是价值,代码如下:

    C语言:

    #include <stdio.h>
    #define max(a, b) ((a)>(b)?(a):(b))
    int f[1001];
    
    int main(void)
    {
     int i, j;
     int m, n;
     int a, b;
     scanf(%d%d, &m, &n);
     for(i = 0; i < n; i++){
     scanf(%d%d, &a, &b);
     for(j = m; j >= a; j--){
     f[j] = max(f[j], f[j - a] + b);
     }
     }
     printf(%d\\n, f[m]);
     return 0;
    }
  • 能量项链 解题报告

    额,花了我三四个小时的时间,终于知道了,是动态规划的题目(我以前做过,不过那个时候真是不知不觉过去的。),我以前只做过背包的题目,这个题目是这暑假以来觉得最复杂的题目了,因为非动态规划的代码一看就能看懂,动态规划的,方程没想通你就看不懂代码!
    我的方程是:f[i][j] = max(f[i][k – i] + f[k][j – k + i] + boll[i] boll[i + j] boll[k])); 其中f[i][j]的意思是从i开始j个珠子的最大能量数,boll[i]是下标为i的珠子的能量。然后就是要注意一下细节,有人的实现方法是使用了长度为200的数组,有人是使用了mod;在这里我是用的后者,用了mod,牺牲了效率,节省了空间。
    这题确实要做下纪念,我的算法水平从今天开始会向新的高度上升,我会站在世界的顶点的!

    C语言:

    #include <stdio.h>
    #define max(a, b) ((a)>(b)?(a):(b))
    unsigned f[100][101];
    int boll[100];
    int n;
    
    int main(void)
    {
     int i, j, k;
     unsigned max = 0;
     scanf(%d, &n);
     for(i = 0; i < n; i++){
     scanf(%d, &boll[i]);
     }
    
     for(j = 2; j <= n; j++){
     for(i = 0; i < n; i++){
     for(k = i + 1; k < i + j; k++){
     f[i][j] = max(f[i][j], f[i][k - i] +
     f[k % n][j - k + i] +
     boll[i] * boll[(i + j) % n] *
     boll[k % n]);
     }
     }
     }
    
     for(i = 0; i < n; i++){
     if(max < f[i][n]){
     max = f[i][n];
     }
     }
    
     printf(%u\\n, max);
     return 0;
    }
  • 数列 结题报告

    这一题先把顺序仔细观察一下,可以发现顺序就是n^0, n^1, n^0 + n^1, n ^ 2, n ^ 0 + n ^2….之类的数据,仔细观察能够发现顺序就是先输出n^i次方,再把所有的n^0 ~ n^i-1 和n^i进行相加。
    嘿嘿,这题我倒是很自豪,发现了数学方法,仔细观察下,就可以发现第m个数字就是,n ^ log 2 (m) + n ^ log 2(m – 2 ^ log 2 (m)) + ….直到n^0为止,嘿嘿,代码如下:

    C语言:

    #include <stdio.h>
    #include <math.h>
    
    int pow_(int num, int x)
    {
     if(x == 0){
     return 1;
     }
     if(x == 1){
     return num;
     }
     if(x & 1){
     return pow_(num * num, x / 2) * num;
     }else{
     return pow_(num * num, x / 2);
     }
    }
    
    int main(void)
    {
     unsigned ans = 0;
     int i, t;
     int m, n;
     scanf(%d%d, &m, &n);
     while(n != 0){
     t = log2(n);
     ans += pow_(m, t);
     n -= pow_(2, t);
     }
     printf(%u\\n, ans);
     return 0;
    }
    

    这题有一个更好的解法,思路是完全的,但是不需要使用log2函数,直接使用位运算,感谢七妹的代码!

    #include <stdio.h>
    
    **int** main(**void**)
    {
     **unsigned** i, j;
     **unsigned** k, n;
     **unsigned** ans = 0, t;
     scanf(%u%u, &k, &n);
     t = 1;
     /* 注意, 从1开始 */
     **while**(n){
     **if**(n & 1){
     ans += t;
     }
     n >>= 1;
     t *= k;
     }
     printf(%d\\n, ans);
     **return** 0;
    }
  • Jam的计数法 解题报告

    这题我用的深搜,写来写去都觉得特别麻烦,干脆把从a到b的所有可能都计算出来,然后判断是否比输入的大,是就输出,让计数器加一,到五就退出程序,等下还优化试下,先把这个的代码贴上来。

    C语言:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    int a, b;
    int n;
    char tmp[27];
    char str[27];
    int count;
    
    void srch(int now)
    {
     int i;
     if(now == n + 1){
     if(strcmp(tmp + 1, str + 1) > 0){
     count++;
     printf(%s\\n, tmp + 1);
     if(count == 5){
     exit(0);
     }
     }
     return ;
     }
     for(i = tmp[now - 1] + 1; i <= b; i++){
     tmp[now] = i;
     srch(now + 1);
     }
    }
    
    int main(void)
    {
     int i;
     scanf(%d%d%d\\n, &a, &b, &n);
     a += \'a\' - 1;
     b += \'a\' - 1;
     scanf(%s, str + 1);
     strcpy(tmp + 1, str + 1);
     *tmp = a - 1;
     srch(1);
     return 0;
    }

    它有可修改的余地,我还想想。
    把开始的时候处理一下,速度会明显快些,代码如下:
    C语言: Jam的计数法 改进版.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    int a, b;
    int n;
    char tmp[26];
    char str[26];
    int count;
    
    void srch(int now, int start)
    {
     int i;
     if(now == n){
     if(strcmp(tmp, str) > 0){
     count++;
     printf(%s\\n, tmp);
     if(count == 5){
     exit(0);
     }
     }
     return ;
     }
     for(i = start; i <= b; i++){
     tmp[now] = i;
     srch(now + 1, i + 1);
     }
    }
    
    int main(void)
    {
     int i;
     scanf(%d%d%d\\n, &a, &b, &n);
     a += \'a\' - 1;
     b += \'a\' - 1;
     scanf(%s, str);
     srch(0, a);
     return 0;
    }
  • 开心的金明 解题报告

    这题可以说就是01背包的例题,我没什么多余的解释,上代码:

    C语言:

    
    #include <stdio.h>
    #define max(a, b) ((a)>(b)?(a):(b))
    int f[30000];
    
    int main(void)
    {
     int n, m;
     int i, j;
     int a, b;
     scanf(%d%d, &n, &m);
     for(i = 0; i < m; i++){
     scanf(%d%d, &a, &b);
     for(j = n; j >= a; j--){
     f[j] = max(f[j], f[j - a] + a * b);
     }
     }
     printf(%d\\n, f[n]);
     return 0;
    }
  • 明明的随机数 解题报告

    这题不难,不过我看到大部分的人都是使用的先用快排再去重,有些人是先去重再用快排,我这里就用的是哈希排序,能够以线性时间(O(n))对所有数据实现排序和去重。
    没什么好解释的,1~1000,把对应的数字放到相应的数组中就可以了。

    #include <stdio.h>
    char bucket[1001];
    
    int main(void)
    {
     int i, t;
     int n, ans = 0;
     scanf(%d, &n);
     for(i = 0; i < n; i++){
     scanf(%d, &t);
     if(!bucket[t]){
     ans++;
     }
     bucket[t] = 1;
     }
     printf(%d\\n, ans);
     t = 0; //判断空格
     for(i = 1; i <= 1000; i++){
     if(bucket[i]){
     if(t){
     printf( );
     }
     t = 1;
     printf(%d, i);
     }
     }
     printf(\\n);
     return 0;
    }
  • NOIP_2002.PJ1:级数求和 解题报告

    这题网上没找到较好的算法(数学方法),只好自己写暴力版本的了。。。这题真的不好做什么报告,提交就是。

    #include <stdio.h>
    
    int main(void)
    {
     double n;
     int i;
     double ans = 0;
     scanf(%lf, &n);
     for(i = 1; ans <= n; i++){
     ans += (double)1.0 / i;
     }
     printf(%d\\n, i - 1);
     return 0;
    }
  • NOIP_2001.PJ2:最大公约数与最小公倍数问题 解题报告

    看到这个题目,不知道怎么做,到网上搜了下最小公倍数和最大公约数之间的公式,就找到了思路,p q = x0 y0..那么我就枚举所有的p,然后求出q,再判断之间的最大公约数是不是x0,就Ok了。

    #include <stdio.h>
    
    int gcd(int x, int y)
    {
     int t;
     while(y > 0){
     t = x % y;
     x = y;
     y = t;
     }
     return x;
    }
    
    int main(void)
    {
     int i, ans = 0; //忘记初始化了... 
     int x, y, t, s;
     scanf(%d%d, &x, &y);
     t = x * y;
     for(i = x; i <= y; i += x){
     s = t / i;
     if((s * i == t) && (gcd(s, i) == x)){
     ans++;
     }
     }
     printf(%d\\n, ans);
     return 0;
    }