2017 Xian ACM Summer Training Warm-up Exercise 3

本文解析了ACM编程竞赛中的四道题目,包括火柴拼数字、字谜、五线谱音符识别及正方形叠放问题。通过算法设计与实现,提供了高效解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

B题Bigger is Better :

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1783

题意:

用有限火柴棍拼数字,能整除m的最大数字。

tip:

f[I][j]用了I根火柴%m为j的最大数字是多少。
最多50位,用高精度,缩位

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
int ca;
const int MOD = 100000000;
int n,m;
struct BigInt{
    int len,a[8];
    void clear(){
        len = 0;//a[1] = 0;//memset(a,0,sizeof(a));
        for(int i =  0 ; i < 8 ; i++)  a[i] = 0;
    }
    void out(){
        for(int i = len ; i >= 1 ; i--){
            if(i != len)  printf("%08d",a[i]);
            else    printf("%d",a[i]);
        }
        if(len == 0)    printf("0");
        printf("\n");
    }
}dp[120][3000];
BigInt Plus(BigInt A,BigInt B){
    if(A.len == 1 &&A.a[1] == 0)    return B;
    BigInt C=A;C.len = max(C.len,B.len)+1;
    for(int i = 1; i <= B.len ;i++) C.a[i] += B.a[i];
    for(int i = 1; i < C.len ; i++) C.a[i+1] += C.a[i]/MOD,C.a[i]%=MOD;
    while(C.len > 0 && C.a[C.len] == 0) C.len--;
    return C;
}
BigInt Mul(BigInt A){
    if(A.len == 1 && A.a[1] == 0)   return A;
    BigInt C;C.clear();
    if(A.len == 0)  return C;
    C.len = A.len+1;
    for(int i = 1; i <= A.len ;i++){
            C.a[i] += A.a[i] * 10;
    }
    for(int i = 1; i < C.len ; i++){
        C.a[i+1] += C.a[i]/MOD;C.a[i] %= MOD;
    }
    while(C.len > 0 && C.a[C.len] == 0) C.len--;

    return C;
}

BigInt IS(int  tnum){
    int num = tnum;
    BigInt AA;AA.len = 1;
    AA.a[1] = tnum;
    return AA;
}
int compare(BigInt A,BigInt B){
    if(A.len > B.len)   return 1;
    if(A.len < B.len)   return -1;
    for(int i = A.len ; i >= 1 ; i--){
        if(A.a[i] > B.a[i]) return 1;
        if(A.a[i] < B.a[i]) return -1;
    }
    return 0;
}

void sov(){
    for(int i = 0 ;i <= n ; i++){
        for(int j = 0 ; j < m ; j++){
            if(dp[i][j].len == 0)   continue;
            BigInt tmp,t;
            tmp = Mul(dp[i][j]);
            if(compare(dp[i+6][(j*10)%m],tmp ) == -1)
               dp[i+6][(j*10)%m] = tmp;
            t = Plus(tmp,IS(1));
            if(compare(dp[i+2][(j*10+1)%m],t) == -1)
                dp[i+2][(j*10+1)%m] = t;
            t = Plus(tmp,IS(2));
            if(compare(dp[i+5][(j*10+2)%m],t) == -1)
                dp[i+5][(j*10+2)%m] = t;
            t = Plus(tmp,IS(3));
            if(compare(dp[i+5][(j*10+3)%m],t)==-1)
                 dp[i+5][(j*10+3)%m] = t;
            t = Plus(tmp,IS(4));
            if(compare(dp[i+4][(j*10+4)%m],t)==-1)
                 dp[i+4][(j*10+4)%m] = t;
            t = Plus(tmp,IS(5));
            if(compare(dp[i+5][(j*10+5)%m],t)==-1)
                 dp[i+5][(j*10+5)%m] = t;
            t = Plus(tmp,IS(6));
            if(compare(dp[i+6][(j*10+6)%m],t)==-1)
                 dp[i+6][(j*10+6)%m] = t;
            t = Plus(tmp,IS(7));
            if(compare(dp[i+3][(j*10+7)%m],t)==-1)
                 dp[i+3][(j*10+7)%m] = t;
            t = Plus(tmp,IS(8));
            if(compare(dp[i+7][(j*10+8)%m],t) == -1)
                 dp[i+7][(j*10+8)%m] = t;
            t = Plus(tmp,IS(9));
            if(compare(dp[i+6][(j*10+9)%m],t)==-1)
                 dp[i+6][(j*10+9)%m] = t;
        }
    }
    BigInt ans;ans.len = 1;ans.a[1]=0;
    int cnt = 0;
    for(int i =  0 ; i <= n ; i++){
        if(dp[i][0].len == 0 ) {
                cnt++;continue;
        }
        if(compare(ans,dp[i][0]) == -1)
            ans = dp[i][0];
    }
    printf("Case %d: ",++ca);
    if(cnt == n && n < 6 )    printf("-1\n");
    else    ans.out();
}
int main(){
   // freopen("out.txt","w",stdout);
    while(~scanf("%d",&n)&&n){
        scanf("%d",&m);
        for(int i =  0 ; i <= n+10 ; i++)
            `
or(int j =  0 ; j <= m ; j++)  dp[i][j].clear();
        dp[0][0].a[1] = 0;dp[0][0].len = 1;
        sov();
    }
}

D题Digit Puzzle :

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1785

题意:

字谜:×× * ×× = ××××
改变给定字谜(不能改位数),但是×和数字可以随便改,使得改变之后的字谜答案是唯一的,问最少改变量时字典序最小的,*比0小

tip:

先一次预处理出来所有答案唯一的字谜,最多99*99个,每个都映射一下,最后只映射了一次的就是答案唯一的,对于每个问题,还是99*99枚举所有的,然后留下改变最少个字典序最小的,每一位都比较一下

#include <cstdio>
#include <iostream>
#include <cstring>
#include <unordered_map>
using namespace std;
unordered_map<unsigned int ,int >mp;
const int N = 10;
const unsigned int hash_star = 10;
char s[N],a[N],b[N],ts[N],ta[N],tb[N],_ans[N];
int lens,lena,lenb,MIN,MINt;
int _a[N],aim[N],ca;
void init(){
    for(int i = 1; i <= 99 ; i++){
        for(int j = 1; j <= 99 ; j++){
            int ans = i*j,k = 0,tmp = 1,jj = j,ii = i,pre =0;
            //if(i == 7&& j == 12)cout <<"i = "<<i <<"  j = "<<j<<"  ans = "<<ans<<endl;

            while(ans){
                _a[++k] = ans%10;
                ans /= 10;
                tmp <<= 1;
            }
            pre = k;
            while(jj){
                _a[++k] = jj %10;
                jj /= 10;
                tmp <<= 1;
            }
            pre = pre*10+k;
            while(ii){
                _a[++k] = ii % 10;
                ii /= 10;
                tmp <<= 1;
            }
            pre = pre*10+k;
            //if(tmp > 512)   cout <<tmp<<endl;
            for(int p = tmp-1 ; p >= 0; p--){
                int tt = p,cnt = k+1;
                long long _hash = pre;
                while(--cnt){
                    if(tt & 1){
                        //if(i == 11&&j == 11&&p == 80)cout <<"a[ "<<cnt <<" ] = "<<_a[cnt]<<endl;
                        _hash =_hash*11 + _a[cnt];
                    }
                    else _hash = _hash*11+hash_star;
                    tt >>= 1;
                }
                //if(i == 1&&j==10)   cout <<"p = "<<p<<"     _ hash = "<<_hash<<endl;
               // if(_hash == 966196) cout << "i = "<<i<<" j  = "<<j<<"  p = "<<p <<endl;
                int kk = mp[_hash];
                if(kk != -1 && kk)
                    mp[_hash] = -1;
                else if(kk == 0) mp[_hash] = 1;
            }
        }
    }
    //cout<<"as = "<<mp[966196]<<endl;
}

void check(){
    for(int i = (lens == 1?1:10); i <= (lens == 1?9:99) ; i++){
        for(int j = (lena == 1?1:10); j <= (lena == 1?9:99) ; j++){
            int ans = i*j,k = 0,tmp = 1,jj = j,ii = i,pre;
            while(ans){
                _a[++k] = ans%10;
                ans /= 10;
                tmp <<= 1;
            }
            pre = k;
            if(k != lenb)   continue;
            while(jj){
                _a[++k] = jj %10;
                jj /= 10;
                tmp <<= 1;
            }
            pre = pre*10+k;
            while(ii){
                _a[++k] = ii % 10;
                ii /= 10;
                tmp <<= 1;
            }
            pre = pre*10+k;
            for(int p = 0 ; p <= tmp-1; p++){
                int tt = p,cnt = k+1,ch = 0,cmp = 0;
                long long _hash = pre;
                while(--cnt){
                    if(tt & 1){
                        cmp = cmp*10+_a[cnt]+1;
                        if(aim[cnt] != _a[cnt])  ch++;
                        _hash =_hash*11 + _a[cnt];
                        _ans[cnt] = _a[cnt]+'0';
                    }
                    else {
                        cmp *= 10;
                        if(aim[cnt] != -1)  ch++;
                        _hash = _hash*11+hash_star;
                        _ans[cnt] = '*';
                    }
                    if(ch > MIN)break;
                    tt >>= 1;
                }

                if(mp[_hash] == 1 && (ch < MIN || (ch == MIN&&cmp < MINt) )){
                     //cout <<"i = "<<i<<"j == "<<j<<"  ch = "<<ch <<endl;
                        //for(int ll = k ; ll >= 1 ; ll--)    cout <<_ans[ll];
                       // cout <<endl;
                    MIN = ch;MINt = cmp;int pp = 0;
                    tb[lenb] = '\0';ta[lena] = '\0';ts[lens] = '\0';
                    for(int ll = lenb-1 ; ll >=0 ; ll--)
                        tb[ll] = _ans[++pp];

                    for(int ll = lena-1 ; ll >=0 ; ll--)
                        ta[ll] = _ans[++pp];
                    for(int ll = lens-1 ; ll >=0 ; ll--)
                        ts[ll] = _ans[++pp];
                }
            }
        }
    }
}
int main(){
    init();
    while(~scanf("%s",s)&& s[0] != '0'){
        scanf("%s%s",a,b);
        lens = strlen(s),lena = strlen(a),lenb = strlen(b);
        int k = 0;
        for(int i = lenb-1 ; i >= 0 ; i--)  aim[++k] = (b[i]=='*')?-1:b[i]-'0';
        for(int i = lena-1 ; i >= 0 ; i--)  aim[++k] = (a[i]=='*')?-1:a[i]-'0';
        for(int i = lens-1 ; i >= 0 ; i--)  aim[++k] = (s[i]=='*')?-1:s[i]-'0';
        //for(int i = 1 ; i <= k ; i++)cout <<"aim[ "<<i<<"  ] = "``
<aim[i]<<endl;
        MIN = MINt = 1000000010;
        check();
        printf("Case %d: %s %s %s\n",++ca,ts,ta,tb);
    }
}

H题Hidden Music Score

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1789

题意:

给定去掉五线谱的线之后那些音符(一个八度内)旋转一定角度之后的坐标,问最开始都是什么音符,给定起始音符,

tip:

给定的时旋转之后的,求出原来的,排序
角度为-60~60且为整数,枚举即可,起始音符给定之后相对sd就一定了,检验是否1~5,相邻的检验是否1sd~5sd,且垂直距离是否sd。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
char p[2],b[2],mp2[10];
int mp1[110],n,ca;
const double eps = 1e-4;
const double pi = acos(-1.0);
const int maxn = 30;
typedef pair<double,double>pdd;
pdd d[maxn],a[maxn];
void init(){
    scanf("%s%s",p,b);
    for(int i = 1; i <= n ; i++){
        scanf("%lf%lf",&a[i].first,&a[i].second);
    }
}
int sign(double k){
    if(fabs(k) < eps)  return 0;
    return k > 0 ? 1:-1;
}
char ans[maxn];
void sov(){
    for(int ro = -60 ; ro <= 60 ; ro++){
        double ang;
        ang=(double)ro*pi/180.0;
        for(int j = 1;j <= n;j++){
            d[j].first = a[j].first * cos(ang) + a[j].second * sin(ang);
            d[j].second = -a[j].first*sin(ang) + a[j].second*cos(ang);
        }
        sort(d+1,d+1+n);
        double sd = (d[n].second - d[1].second)/(mp1[b[0]]-mp1[p[0]]);double real = 2.0*sd;
        if(sign(real-5.0) > 0 || sign(1.0-real) > 0)  continue;
        int j;
        for(j = 2; j <= n ; j++){
            double k = d[j].first-d[j-1].first,pp = (d[j].second - d[1].second);
            int ct = pp/sd;
            int flag = 0;
            if(sign((ct-1)*sd-pp)==0)   ans[j] = mp2[mp1[p[0]]+ct-1];
            else if(sign(ct*sd-pp)==0)  ans[j] = mp2[mp1[p[0]]+ct];
            else if(sign((ct+1)*sd-pp) == 0)   ans[j] = mp2[mp1[p[0]]+ct+1];
            else   break;
            if(sign(1.0*real-k) > 0 || sign(k-5.0*real) > 0)  break;
        }
        if(j == n+1 && ans[n] == b[0])    break;
    }
    printf("Case %d: %c",++ca,p[0]);
    for(int i = 2; i <= n ; i++){
        printf("%c",ans[i]);
    }
    printf("\n");
}
void pre(){
    mp1['C']=0,mp1['D']=1,mp1['E']=2;mp1['F']=3,mp1['G']=4,mp1['A']=5;mp1['B']=6;
    mp2[0]='C',mp2[1]='D',mp2[2]='E';mp2[3]='F',mp2[4]='G',mp2[5]='A';mp2[6]='B';
}
int main(){
    pre();
    while(~scanf(
"%d",&n) && n){
        init();
        sov();
    }

}

J题Overlapping Squares :

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1791
搜索枚举

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn = 20;
char ini[maxn][maxn],tmp[maxn][maxn];
int vis[maxn],ca;
void init(){
    for(int i =  1 ; i < 5; i++){
        gets(ini[i]);
       // puts(ini[i]);
       // cout <<endl;
    }
    memset(vis,0,sizeof(vis));
    for(int i = 0 ; i < 5; i++){
        for(int j = 0 ; j < 9 ; j++){
            tmp[i][j] = ' ';
        }
    }
}
//void print(){
//    //if(step != 1)   return ;
//    printf("t: \n");
//    for(int i = 0 ; i < 5 ; i++){
//        for(int j =  0 ; j < 9 ; j++)
//        printf("%c ",t[i][j]);
//        printf("\n");
//    }
//    for(int i = 0 ; i < 5 ; i++){
//        for(int j =  0 ; j < 9 ; j++)
//        printf("%c ",ini[i][j]);
//        printf("\n");
//    }
//    int l;
//    scanf("%d",&l);
//}
int check(int step){
   // print(step);
    for(int i = 0 ; i < 5 ; i++)
        for(int j =  0 ; j < 9 ; j++)
            if(tmp[i][j] != ini[i][j])  return 0;
    return 1;
}
//void book(){
//    for(int i =  0 ; i < 5 ;i++){
//        for(int j = 0 ; j < 9 ; j++)
//            t[i][j] = tmp[i][j];
//    }
//    print();
//}
//void re(){
//    for(int i =  0 ; i < 5 ;i++){
//        for(int j = 0 ; j < 9 ; j++)
//            tmp[i][j] = t[i][j];
//    }
//    print();
//}
void tryput(int pos){
    int r = pos/3;
    int c = (pos%3)*2;
    tmp[r+1][c] = tmp[r+2][c] = tmp[r+1][c+4] = tmp[r+2][c+4] = '|';
    tmp[r][c+1] = tmp[r][c+3] = tmp[r+2][c+1] = tmp[r+2][c+3] = '_';
    tmp[r+1][c+1] = tmp[r+1][c+2] = tmp[r+2][c+2] = tmp[r+1][c+3] = ' ';
}
int dfs(int step){
    if(step > 6)    return 0;
    if(check(step)) return 1;
    char t[maxn][maxn];
    for(int i =  0 ; i < 5 ;i++){
        for(int j = 0 ; j < 9 ; j++)
            t[i][j] = tmp[i][j];
    }
    for(int i = 0 ; i < 9 ; i++){
        if(vis[i])  continue;
        vis[i] = 1;
        tryput(i);
        if(dfs(step+1)) return 1;
        vis[i] = 0;
        for(int i =  0 ; i < 5 ;i++){
            for(int j = 0 ; j < 9 ; j++)
                tmp[i][j] = t[i][j];
        }
    }
    return 0;
}
int main(){
    while(gets(ini[0]) && ini[0][0] != '0'){
        init();
        if(dfs(0))  printf("Case %d: Yes\n",++ca);
        else   printf("Case %d: No\n",++ca);
    }
}
/*
         #
 _ _ _   #
| |_ _|  #
|_|   |  #
  |_ _|  #
         #
   _ _   #
  |   |  #
  |_ _|  #
         #
 _ _ _ _ #
|_|_|_|_|#
|_|_|_|_|#
|_|_|_|_|#
|_|_|_|_|#
   _ _   #
 _|   |_ #
| |_ _| |#
|_|   |_|#
  |_ _|_|#
0

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值