Section 2.2
Preface Numbering
罗马数字的处理,问从1-N,各个IVX...什么的出现了多少次。
我们可以用IVX表示出1-9
XLC表示出10-90
CDM表示出100-900
统计出怎么出现的。接下来从高位往下减来表示就好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
Subset Sums
从1-N的数分成两块使得他们各自的和相等。N<=39
可以算出所有的和。若为奇数,一定不能分成两块。
否则算出每块和后简单的背包就好了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
Runaround Numbers
http://www.wzoi.org/usaco/12%5C205.asp 题意
没想到怎么做,如果真要硬做的话估计就暴力一个个往上找。
然而居然真的是这样。。。然而不知道怎么证明为什么一定可以找到一个。感觉程序还有不完善的地方,比如应该判断当大于几位数后就结束。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
Party Lamps
N盏灯(N<=100),一开始都是开着的。有4个开关,分别可以使:全部的灯,奇数号灯,偶数号灯,3* k+1号灯改变状态。一共操作C次
给出某几盏灯必须是什么状态,求出所有的灯的状态的可能性。
可以发现对一个开关开关两次后就相当于没有动过他,所以其实一共只有2^4中情况。其余的只要c-1的个数是偶数即可以让剩余操作抵消即可。
所以暴力枚举16中情况。
当没有可行状况要输出IMPOSSIBLE
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }
优化:
1.有开关奇数偶数=开关全部的灯,可以继续减少情况。
2.所有的灯以6为一个循环。所以只用存6个的状态就好,这样去重也方便。