11
15
2012
0

HIT Training Camp II 解题报告

这次练习的contest地址

http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=17168

本次的题目分别是 

Uva 10624 Super Number

Uva 10791 Minimum Sum LCM

UVa 10118 Free Candies

Uva 712 S-Trees

HDU 4453 Looploop

 


 

A. Super Number

题目大意:
   给出n和m,求出一个m位数,使得第i位(n≤i≤m)满足前i位表示的数字是i的倍数;要求这个m位数要尽量小
简单分析:
   签到+热身题
   DFS即可,可能有时会超时,小优化+拼RP一下吧
 
#include<stdio.h>
int n,m,a[50];

bool judge(int x)
{
     int s=0;
     for(int i=0; i<x; i++)
          s=(s*10+a[i])%x;
     return !s;
}
bool dfs(int x)
{
     if(x==m)return 1;
     for(int i=0; i<10; i++) {
          a[x]=i;
          if((x<n-1 || judge(x+1))&& dfs(x+1))return 1;
     }
     return 0;
}
int main()
{
     int T,t;
     scanf("%d",&T);
     for(t = 0; t < T; ++t) {
          int i, found=0;
          scanf("%d%d",&n,&m);
          for(i=1; i<10; ++i) {
               a[0]=i;
               if(dfs(1)) {
                    found=1;
                    break;
               }
          }
          printf("Case %d: ",t+1);
          if(found) {
               for(i=0; i<m; ++i) printf("%d",a[i]);
               printf("\n");
          } else printf("-1\n");
     }
     return 0;
}

 


B. Minimum Sum LCM

题目大意:
   给定一个N,求出最小共倍数为N的所有不同方案的数中的最小的和。
简单分析:
   最小共倍数的任一因子个数和每个数中这个因子个数的最大值相等,让每个数恰巧就是只包含一个因子所有数的和就能保证最小。
   注意两种特殊情况:
      1、lcm中只有一种因子,比如16 
      2、lcm为一个素数

 

#include <cstdio>
#include <cmath>

int main()
{
     int n;
     int t = 1;
     while(scanf("%d",&n) ,n) {
          printf("Case %d: ",t++);
          int m = sqrt((float)n);
          int ans = 0;
          int tmpn = n;
          int count = 0;
          for(int i = 2; i <= m; ++i) {
               if(tmpn % i == 0) {
                    ++count;
                    int  tmp = 1;
                    while(tmpn % i == 0) {
                         tmp *= i;
                         tmpn /= i ;
                    }
                    ans += tmp;
               }
          }
          if(tmpn == n) printf("%lld\n",(long long)1 + n);
          else {
               if(tmpn != 1) ans += tmpn;
               else if(count == 1) ans++;
               printf("%d\n",ans);
          }
     }
     return 0;
}

 

C. Free Candies

题目大意:
   有4堆糖果,每堆有n(最多40)个,有一个篮子,最多装5个糖果,我们每次只能从某一堆糖果里拿出一个糖果,如果篮子里有两个相同的糖果,那么就可以把这两个(一对)糖果放进自己的口袋里,问最多能拿走多少对糖果。糖果种类最多20种.
简单分析:
   DP或者记忆化搜索
 
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=50;
int n,kind[25],data[N][N],map[N][N][N][N];
bool vis[N][N][N][N];
int dp(int,int,int,int);
int tot();
int main()
{
     while(scanf("%d",&n)!=EOF) {
          if(n==0) break;
          memset(map,0,sizeof(map));
          memset(vis,0,sizeof(vis));
          memset(data,0,sizeof(data));
          memset(kind,0,sizeof(kind));
          for(int i=0; i<n; i++)
               for(int j=0; j<4; j++)
                    scanf("%d", &data[i][j]);
          printf("%d\n",dp(0,0,0,0));
     }
     return 0;
}
int dp(int a,int b,int c,int d)
{
     bool &flag = vis[a][b][c][d];
     int &ans = map[a][b][c][d];
     if(flag) return ans;
     else if (tot() == 5 || (a==n && b==n && c==n && d==n) ) {
          flag = 1;
          ans = 0;
          return 0;
     } else {
          if(a < n) {
               kind[data[a][0]] ^= 1;
               ans = max(ans,dp(a+1,b,c,d)+(kind[data[a][0]]==0));
               kind[data[a][0]] ^= 1;
          }
          if(b < n) {
               kind[data[b][1]] ^= 1;
               ans = max(ans,dp(a,b+1,c,d)+(kind[data[b][1]]==0));
               kind[data[b][1]] ^= 1;
          }
          if(c < n) {
               kind[data[c][2]] ^= 1;
               ans = max(ans,dp(a,b,c+1,d)+(kind[data[c][2]]==0));
               kind[data[c][2]] ^= 1;
          }
          if(d < n) {
               kind[data[d][3]] ^= 1;
               ans = max(ans,dp(a,b,c,d+1)+(kind[data[d][3]]==0));
               kind[data[d][3]] ^= 1;
          }
          flag = 1;
          return ans;
     }
}
int tot()
{
     int ret=0;
     for(int i=0; i<25; i++) if(kind[i]) ++ret;
     return ret;
}

 

D. S-Trees

题目大意:
   可以这样理解:有一排盒子,盒子上标有01,盒子上是一个树结构,m个小球从树顶向下落,遇到0左落遇到1又落,判断有没有落到标记有1的盒子里。
简单分析:
   模拟建树,模拟下落。这题就是读题有点小恶,算法很简单。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>

using namespace std;

struct node {
     string name;
     char v;
     node *left;
     node *right;
};
int n, cnt;
string name[1200];
node *newnode(string name)
{
     node *u = new node;
     u->name = name;
     u->right = u->left = NULL;
     u->v = '0';
     return u;
}
node *build_tree(string name[], int ter, string temp)
{
     if(ter == n) {
          node *s = newnode(name[ter]);
          s -> v = temp[cnt ++];
          return s;
     } else {
          node *s = newnode(name[ter]);
          s->left = build_tree(name, ter + 1, temp);
          s->right = build_tree(name, ter + 1, temp);
          return s;
     }
}

char dfs(node *root, string x)
{
     node *u = root;
     int i;
     for(i = 0; i < n; i ++) {
          if(x[i] == '0')
               u = u->left;
          else u = u->right;
     }
     return u->v;
}

int main()
{
     int i, cas = 0;
     while(scanf("%d", &n) != EOF && n) {
          for(i = 0; i < n; i ++)
               cin >> name[i];
          string temp;
          cin >> temp;
          cnt = 0;
          node *root = build_tree(name, 0, temp);
          cout << "S-Tree #"<< ++cas << ":" << endl;
          int m;
          scanf("%d", &m);
          for(i = 0; i < m; i ++) {
               string t;
               cin >> t;
               cout << dfs(root, t);
          }
          printf("\n\n");
     }
     return 0;
}

 

D. Looploop

题目大意:
   题目中定义了六种操作,详见题目,不难理解。
简单分析:
   双端队列Dequeue的应用
//转自 http://www.cnblogs.com/shen1000/archive/2012/11/08/2761692.html
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
struct Root {
     deque<int>que1,que2,que3;
     int _add;
     bool head;
     //初始化
     void init(int k1,int k2,int n) {
          _add=0;
          head=true;
          while(!que1.empty())que1.pop_back();
          while(!que2.empty())que2.pop_back();
          while(!que3.empty())que3.pop_back();
          int tmp;
          for(int i=0; i<k1; i++) {
               scanf("%d",&tmp);
               que1.push_back(tmp);
          }
          for(int i=k1; i<k2; i++) {
               scanf("%d",&tmp);
               que2.push_back(tmp);
          }
          for(int i=k2; i<n; i++) {
               scanf("%d",&tmp);
               que3.push_front(tmp);
          }

     }
     //插入一个x,由于是顺时针在指针之后插入
     //这样插入之后整就要向顺时针移动一次
     //如果que1的第一个在que3中,则只需把x插入que1,然后move(1)即可
     void insert(int x) {
          if(head) {
               que3.push_front(que1.front()+_add);
               que1.pop_front();
               que1.push_front(x-_add);
          } else {
               que3.push_front(que1.back()+_add);
               que1.pop_back();
               que1.push_back(x-_add);
          }
          move(1);
     }
     //删除一个元素整体要逆时针移动一次
     //那我们就先逆时针移动一次,也就是move(2)
     //然后删除que3的ront即可
     void _delete() {
          move(2);
          que3.pop_front();
     }
     //翻转时只需翻转标记位即可
     void reverse() {
          head=!head;
     }
     //加x时只需加延迟标记位即可
     void add(int x) {
          _add+=x;
     }
     //移动时比较繁琐,不过思路较简单
     //左移相当于逆时针旋转一次
     //右移相当于顺时针旋转一次
     void move(int x) {
          if(x==1) {
               if(head) {
                    que1.push_front(que3.front()-_add);
                    que3.pop_front();
                    que2.push_front(que1.back());
                    que1.pop_back();
                    que3.push_back(que2.back()+_add);
                    que2.pop_back();
               } else {
                    que1.push_back(que3.front()-_add);
                    que3.pop_front();
                    que2.push_front(que1.front());
                    que1.pop_front();
                    que3.push_back(que2.back()+_add);
                    que2.pop_back();
               }
          } else {
               if(head) {
                    que3.push_front(que1.front()+_add);
                    que1.pop_front();
                    que1.push_back(que2.front());
                    que2.pop_front();
                    que2.push_back(que3.back()-_add);
                    que3.pop_back();
               } else {
                    que3.push_front(que1.back()+_add);
                    que1.pop_back();
                    que1.push_front(que2.front());
                    que2.pop_front();
                    que2.push_back(que3.back()-_add);
                    que3.pop_back();
               }
          }
     }
     //询问时返回实际值即可
     int query() {
          if(head) {
               return que1.front()+_add;
          } else {
               return que1.back()+_add;
          }
     }

} root;

int main()
{
     int m,tmp,n,k1,k2;
     char op[10];
     int ca=1;
     while(scanf("%d%d%d%d",&n,&m,&k1,&k2),n) {
          root.init(k1,k2,n);
          printf("Case #%d:\n",ca++);
          while(m--) {
               scanf("%s",op);
               switch(op[0]) {
               case 'a':
                    scanf("%d",&tmp);
                    root.add(tmp);
                    break;
               case 'r':
                    root.reverse();
                    break;
               case 'i':
                    scanf("%d",&tmp);
                    root.insert(tmp);
                    break;
               case 'd':
                    root._delete();
                    break;
               case 'm':
                    scanf("%d",&tmp);
                    root.move(tmp);
                    break;
               case 'q':
                    printf("%d\n",root.query());
                    break;
               }
          }
     }
     return 0;
}

 

Category: ICPC | Tags: Algorithm
8
27
2012
38

C++ Primer 4th Edition 学习笔记

      大二的Jingo需要到二校区给学弟们当C\C++程序设计实验课的TA,为了不出现各种XXOO而Jingo解决不了的事情,外加因为一直不按照C++标准去写程序,C\C++特性乱用的Jingo的确想改一下自己写代码的风格习惯,趁着前几周课程不紧,Jingo决定拜读学习一下《C++ Primer 4th Edition》。为了监督自己的学习和备忘,Jingo每天要记下一点学习笔记。

第2章 变量和基本类型

      C++的每一种变量规定了最小的存储空间;
      可以给unsigned的类型赋值为负数、超过范围的数,需要%256、65536这样的数;
      整形中,0开头比如024为八进制(octal),十六进制(hexadecimal)0x或0X开头;
      整形字面值后加L、U;
      浮点字面值后可加F、L,默认为double;  1024f是不正确的;
      转义序列\000(octal)、\xddd(hexadecimal)
      多行语句可以在行末加\链接起来;
cou/
t << en/
dl;
      标识符不能包含两个连续的下划线,也不能下划线开头后紧跟一个大写字母;
      非const引用只能绑定到与该引用同类型的对象;
      const引用能绑定到不同类型或者绑定到右值;
     
double dval=3.14;
const int &ri=dval;
      非const变量默认为extern,const默认为局部变量;
      枚举型示例:
enum Point {
    point2d = 2, point2w, point3d = 3, point3w
};   
      于是 point2d = 2,point2w = 3, point3d = 3,point3w = 4;
 
 
第3章 标准库类型
 
      cin读入string时,读到空白字符,读取终止(空白字符留在输入流中);
      getline读入时,遇到换行符终止读入并丢弃换行符;
      string::size_type,verctor<int>::size_type不要把size返回给int变量;
      string s5 = s4+","+"world";这样ok;
      string s6 = "hello"+","+s2;这样不正确;
      cctype中的isalum(c)数字或字字母之类的函数;
      vector<T> v(n) 默认初始化n个值;
      vector(a+2,a+4) 用数组初始化vector;
      C++习惯用!=;
      改变vector长度之后,不要信赖原有的迭代器;
      bitset<32> bitvec("1100") string类型倒序初始化;
      bitset<32> bitvec(str,5,4) 第5个开始4个字符;
      bitset<32> bitvec(str,str.size()-4) 只用后四位;
      site_t 在cstddef中定义的与机器相关的无符号整数;
 
第4章 数组和指针
 
      void*指针支持操作:
          与另一指针比较;
          先函数传递void*指针或从函数返回void*指针;
          给另一个void*指针赋值;
          不允许使用void*指针操纵它所指向的对象;
      cstddef中定义了ptrdiff_t这是一种与机器有关的有符号类型;
      指针指向数组某个元素后可以 k = p[-2]
      const int *p为const指针,是一个自认为指向const变量的指针;
      int *const p为指针常量,不可改变指针存储的地址;
      定义const int p = 2后,不能让一个非const指针指向p;
     
typedef string *pstring;
const pstring cstr;
pstring const cstr;
string *const cstr;
//以上三种定义形式等价
      创建动态数组并用初始值初始化int *pia = new int[10]();
      删除一个动态数组 delete [] pia;
      char *str = st2.c_str();
int ia[3][4];
int (*ip)[4];
ip = &ia[2];

typedef int int_array[4];
int_array *ip=ia;

for (int_array *p = ia; p != ia + 3; ++p)
     for (int *q = *p; q != *p + 4; ++q)
         cout << *q << endl;
     
 
第5章 表达式
 
      只在有必要时才用后置操作符;
      *iter++代表*(iter++)先使用原值解引用,再++,对比(*iter)++和*++iter;
     
int x[10];
int *p = x;
cout << sizeof(x)/sizeof(*x) << endl; //数组长度
cout << sizeof(p)/sizeof(*p) << endl; //与机器有关,返回指针大小/int大小
     
     
       dynamic_cast用于支持运行时识别指针或引用所指向的对象,目前用途不太明确,mark一下;
     const_cast转换const状态;
     int a = static_cast<int>(b);
     reinterpret_cast将操作数内容解释为另一种不同的类型;
 
第6章 语句
 
       悬垂else;
     异常处理代码中,try\throw\catch的使用先mark一下
     预处理宏,assert()是一个宏,现代C++程序很少使用预处理宏。
 
 
第7章 函数
 
       尽量用const引用不被修改的形参;
     f(int (&arr)[10])传递数组的引用,数组元素个数确定。
     f(int (*matrix)[10]) 与 f(int matrix[][10])等价;
 
#include <iostream>

using namespace std;

int main(int argc, char* argv[])
{
     for (int i = 0; i != argc; ++i) {
          cout << argv[i] << endl;
     }
     return 0;
}
    
     varargs的用法,先Mark;
 

 

Category: Programming Language | Tags: c++

| Theme: Aeros 2.0 by TheBuckmaker.com