Section 2.2

Preface Numbering

罗马数字的处理,问从1-N,各个IVX...什么的出现了多少次。

我们可以用IVX表示出1-9

XLC表示出10-90

CDM表示出100-900

 

统计出怎么出现的。接下来从高位往下减来表示就好了。

#include <bits/stdc++.h>
using namespace std;
char dir[10] = {'I', 'V', 'X', 'L', 'C', 'D', 'M'};
int cnt[10][3];
int ans[10];
void init(){
    int i;
    for(i = 1; i < 4; i++){
        cnt[i][0] = i;
    }
    cnt[4][0] = cnt[4][1] = 1;
    cnt[5][1] = 1;
    for(i = 6; i < 9; i++){
        cnt[i][0] = i-5; cnt[i][1] = 1;
    }
    cnt[9][0] = cnt[9][2] = 1;
}

void gao(int x, int base){
    for(int i = 0; i < 3; i++){
     //   cout<<x<<" " << cnt[x][i] <<endl;
        ans[base+i] += cnt[x][i];
    }
}

int main()
{
    freopen("preface.in","r",stdin);
    #ifndef poi
    freopen("preface.out","w",stdout);
    #endif
    init();
    int n, i, j, x;
    cin >> n;
    for(i = 1; i <= n; i++){
        x = i;
        if(x >= 1000){
            ans[6] += x / 1000;
            x -= (x/1000)*1000;
        }
        if(x >= 100){
            gao(x/100, 4);
            x-= (x/100)*100;
        }
        if(x >= 10){
            gao(x/10, 2);
            x-= x/10*10;
        }
        if(x>0){
            //printf("!!%d\n", x);
            gao(x, 0);
        }
    }
    for(i = 0 ; i <= 6; i++){
        if(ans[i]){
            cout << dir[i] <<" " << ans[i] <<endl;
        }
    }
    return 0;
}
View Code

Subset Sums

从1-N的数分成两块使得他们各自的和相等。N<=39

 

可以算出所有的和。若为奇数,一定不能分成两块。

否则算出每块和后简单的背包就好了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1005;
ll dp[N];
int main()
{
    freopen("subset.in","r",stdin);
    #ifndef poi
    freopen("subset.out","w",stdout);
    #endif
    int n, i, j, m;
    cin >> n;
    dp[0] = 1;
    m = (n+1)*n/2;
    if(m&1) {
        cout << 0 <<endl;
        return 0;
    }
    m/=2;
    for(i = 1; i <= n; i++){
        for(j = m; j >= 0; j--){
            if(dp[j] && i + j <= m)   {
                dp[j+i] += dp[j];
            }
        }
    }
    cout << dp[m] / 2<< endl;
}
View Code

Runaround Numbers

http://www.wzoi.org/usaco/12%5C205.asp 题意

 

没想到怎么做,如果真要硬做的话估计就暴力一个个往上找。

然而居然真的是这样。。。然而不知道怎么证明为什么一定可以找到一个。感觉程序还有不完善的地方,比如应该判断当大于几位数后就结束。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N  = 14;
bool vis[N];
char str[N];
int len = 0;
int go(int now, int step){
    step %= len;
    return (now - step + len) % len;
}
bool gao(int x){
    memset(vis, false, sizeof(vis));
    int tp = x, i, now; len = 0;
    while(tp){
        str[len++] = tp%10;
        if(vis[tp%10])return false;
        vis[tp%10] = true;
        tp /= 10;
    }

    memset(vis, false, sizeof(vis));
    now = 0;
    for(int k = 1; k < len; k++){
        vis[now] =true;
        now = go(now, str[now]);
        if(vis[now])    return false;
    }
    now = go(now, str[now]);
    if(now == 0)    return true;
    return false;

}

int main()
{
    freopen("runround.in","r",stdin);
    #ifndef poi
    freopen("runround.out","w",stdout);
    #endif
    ll n;
    cin >> n;   n++;
    for(; ; n++){
       // cout << n << endl;
        if(gao(n))  break;
    }
    cout <<n <<endl;
    return 0;

}
View Code

Party Lamps

N盏灯(N<=100),一开始都是开着的。有4个开关,分别可以使:全部的灯,奇数号灯,偶数号灯,3* k+1号灯改变状态。一共操作C次

给出某几盏灯必须是什么状态,求出所有的灯的状态的可能性。

 

可以发现对一个开关开关两次后就相当于没有动过他,所以其实一共只有2^4中情况。其余的只要c-1的个数是偶数即可以让剩余操作抵消即可。

所以暴力枚举16中情况。

 

当没有可行状况要输出IMPOSSIBLE

#include <bits/stdc++.h>
using namespace std;
const int N = 34;
const int M = 104;
bool  ans[N][M], same[N][N];
int n, c, id = 0;
bool on[M], off[M];
int f[N];

void gao(int x){
    int one = 0, tp = x, i;
    while(tp){
        one += (tp&1);
        tp >>= 1;
    }
    if(c - one < 0 || ((c - one)&1))    return;
   // printf("%d\n", x);
    ++id;
    for(i = 1; i <= n; i++) ans[id][i] = 1;
    if(x&1) for(i = 1; i <= n; i++) ans[id][i] ^= 1;
    if(x&2) for(i = 1; i <= n; i += 2) ans[id][i] ^= 1;
    if(x&4) for(i = 2; i <= n; i+= 2)   ans[id][i] ^= 1;
    if(x&8) for(i = 1; i <= n; i+= 3)   ans[id][i] ^= 1;
    //f[id] = id;
    for(i = 1; i <= n; i++){
      //  printf("%d %d\n", i, ans[id][i]);
        if(on[i]&& !ans[id][i]){
            id --;  return;
        }
        if(off[i]&&ans[id][i]){
            id--;   break;
        }
    }

}

bool mor(int j, int k){
    int i;

    for(i = 1; i <= n; i++){
        if(ans[j][i] > ans[k][i]) return true;
        if(ans[j][i] < ans[k][i]) return false;
    }
    same[j][k] = same[k][j] = true;

}
int main()
{
    freopen("lamps.in","r",stdin);
    #ifndef poi
    freopen("lamps.out","w",stdout);
    #endif
    int i, j, t;
    cin >> n >> c;
    while(cin >> t){
        if(t == -1) break;
        on[t] = true;
    }while(cin>>t){
        if(t == -1) break;
        off[t] = true;
    }
    int limit = (1<<4);
    for(i = 0; i < limit; i++){
        //printf("%d\n", i);
        gao(i);
    }
    for(i = 1; i <= id; i++)f[i] = i;
    for(i = 1; i <= id; i++){
        for(j = 1; j <= id-i; j++){
            if(mor(f[j], f[j+1])) swap(f[j], f[j+1]);
        }
    }
    for(i = 1; i <= id; i++){
        if(same[i][i-1])    continue;
        for(j = 1; j <= n; j++){
            printf("%d", ans[f[i]][j]);
        }
        printf("\n");
    }
    if(id == 0) printf("IMPOSSIBLE\n");
    return 0;

}
View Code

 

优化:

1.有开关奇数偶数=开关全部的灯,可以继续减少情况。

2.所有的灯以6为一个循环。所以只用存6个的状态就好,这样去重也方便。

posted @ 2015-07-18 00:34  bbbbq  阅读(170)  评论(0编辑  收藏  举报