哈尔滨理工大学软件与微电子学院第八届程序设计竞赛同步赛(高年级) Solution
A:
Solved.
分别处理出每个%7后余数的数字个数,再组合一下
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 int n, m; 6 ll cnt[2][10]; 7 8 ll calc(ll x, ll y) 9 { 10 if (x % 7 >= y) return x / 7 + 1; 11 return x / 7; 12 } 13 14 int main() 15 { 16 while (scanf("%d%d", &n, &m) != EOF) 17 { 18 memset(cnt, 0, sizeof cnt); 19 for (int i = 0; i < 7; ++i) 20 { 21 cnt[0][i] += calc(n, i); 22 cnt[1][i] += calc(m, i); 23 } 24 ll res = 0; 25 --cnt[0][0], --cnt[1][0]; 26 cnt[1][7] = cnt[1][0]; 27 for (int i = 0; i < 7; ++i) 28 res += cnt[0][i] * cnt[1][7 - i]; 29 printf("%lld\n", res); 30 } 31 return 0; 32 }
B:
Solved.
状压DP.
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 int n,m; 6 ll f[12][1<<11]; 7 bool ins[1<<11]; 8 int main(){ 9 while(cin>>n>>m&&n){ 10 for(int i=0;i<(1<<m);i++){ 11 bool cnt=0,hasodd=0; 12 for(int j=0;j<m;j++) 13 if((i>>j)&1)hasodd|=cnt,cnt=0; 14 else cnt^=1; 15 ins[i]=hasodd|cnt?0:1; 16 17 } 18 f[0][0]=1; 19 for(int i=1;i<=n;i++) 20 for(int j=0;j<(1<<m);j++){ 21 f[i][j]=0; 22 for(int k=0;k<(1<<m);k++){ 23 if((j&k)==0&&ins[j|k]) 24 f[i][j]+=f[i-1][k]; 25 } 26 27 } 28 cout<<f[n][0]<<endl; 29 } 30 }
C:
Solved.
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 int n, s; 6 7 int main() 8 { 9 while(~scanf("%d %d", &n, &s)) 10 { 11 int Min = 0x3f3f3f3f; 12 for(int i = 0; i < n; ++i) 13 { 14 int num = 0; 15 scanf("%d" , &num); 16 Min = min(Min, num); 17 } 18 printf("%d\n", s * Min); 19 } 20 return 0; 21 }
D:
Solved.
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1010; 6 int n, s; 7 int arr[maxn]; 8 9 int main() 10 { 11 while(~scanf("%d %d", &n, &s)) 12 { 13 for(int i = 1; i <= n; ++i) 14 { 15 scanf("%d", arr + i); 16 } 17 sort(arr + 1, arr + 1 + n); 18 printf("%d\n", arr[n - 2] * s); 19 } 20 return 0; 21 }
E:
Solved.
最长公共子序列。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1010; 4 int f[maxn][maxn]; 5 char s1[maxn],s2[maxn]; 6 int main(){ 7 cin>>s1+1>>s2+1; 8 int n=strlen(s1+1),m=strlen(s2+1); 9 for(int i=1;i<=n;i++) 10 { 11 12 for(int j=1;j<=m;j++) 13 { 14 f[i][j]=max(f[i - 1][j], f[i][j - 1]); 15 if(s1[i]==s2[j]) 16 { 17 f[i][j]=max(f[i][j],f[i-1][j-1] + 1); 18 } 19 20 } 21 } 22 printf("%d\n",f[n][m]); 23 }
F:
Solved.
$dp[i][j][k] 表示到达i, j 的时候步数为k的方案数$
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=210; 5 const ll MOD = 1e9 + 7; 6 ll dp[maxn][maxn][maxn]; 7 int fx[8][2]={{1,2},{1,-2},{-1,2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}}; 8 int n,m,s; 9 inline bool check(int x,int y){ 10 if(x<1 || x>n || y<1 ||y>m)return false; 11 return true; 12 } 13 int main(){ 14 while(cin>>n>>m>>s) 15 { 16 memset(dp, 0, sizeof dp); 17 dp[1][1][0]=1; 18 for(int k=1;k<=s;k++) 19 { 20 for(int i=1;i<=n;i++) 21 { 22 for(int j=1;j<=m;j++){ 23 for(int t=0;t<8;t++) 24 { 25 int x=i+fx[t][0]; 26 int y=j+fx[t][1]; 27 if(check(x,y)){ 28 dp[i][j][k]+=dp[x][y][k-1]; 29 dp[i][j][k]%=MOD; 30 } 31 } 32 } 33 } 34 } 35 cout<<dp[n][m][s]<<endl; 36 } 37 }
G:
Unsolved.
H:
Solved.
考虑离线,对$每个数处理出到L左边离它最近的非互质的数,以及到R右边$离它最近的非互质的数,
再考虑先固定$l, 对每一个r处理出答案$
再考虑什么时候把数的贡献加进去,仅当这个数的$L < l 的时候便可以加入贡献,贡献的范围是[pos, R - 1], pos 表示那个数的位置$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define pii pair <int, int> 6 int n, q, a[N], l[N], r[N], dp[N], ans[N], vis[N]; 7 vector <int> fac[N]; 8 vector <pii> v[N], qv[N]; 9 10 namespace SEG 11 { 12 int a[N << 2], lazy[N << 2]; 13 void build(int id, int l, int r) 14 { 15 a[id] = 0; 16 if (l == r) return; 17 int mid = (l + r) >> 1; 18 build(id << 1, l, mid); 19 build(id << 1 | 1, mid + 1, r); 20 } 21 void pushdown(int id, int l, int r, int mid) 22 { 23 if (!lazy[id]) return; 24 lazy[id << 1] += lazy[id]; 25 a[id << 1] += lazy[id] * (mid - l + 1); 26 lazy[id << 1 | 1] += lazy[id]; 27 a[id << 1 | 1] += lazy[id] * (r - mid); 28 lazy[id] = 0; 29 } 30 void pushup(int id) { a[id] = a[id << 1] + a[id << 1 | 1]; } 31 void update(int id, int l, int r, int ql, int qr, int val) 32 { 33 if (l >= ql && r <= qr) 34 { 35 a[id] += val * (r - l + 1); 36 lazy[id] += val; 37 return; 38 } 39 int mid = (l + r) >> 1; 40 pushdown(id, l, r, mid); 41 if (ql <= mid) update(id << 1, l, mid, ql, qr, val); 42 if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, val); 43 pushup(id); 44 } 45 int query(int id, int l, int r, int pos) 46 { 47 if (l == r) return a[id]; 48 int mid = (l + r) >> 1; 49 pushdown(id, l, r, mid); 50 if (pos <= mid) return query(id << 1, l, mid, pos); 51 else return query(id << 1 | 1, mid + 1, r, pos); 52 } 53 } 54 55 void init() 56 { 57 for (int i = 2; i <= 100000; ++i) 58 { 59 if (vis[i]) continue; 60 fac[i].push_back(i); 61 for (int j = 2 * i; j <= 100000; j += i) 62 { 63 vis[j] = 1; 64 fac[j].push_back(i); 65 } 66 } 67 } 68 69 int main() 70 { 71 init(); 72 while (scanf("%d%d", &n, &q) != EOF) 73 { 74 for (int i = 0; i <= n + 1; ++i) l[i] = 0, r[i] = n + 1, v[i].clear(), qv[i].clear(); 75 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 76 memset(vis, 0, sizeof vis); 77 for (int i = 1; i <= n; ++i) 78 for (auto it : fac[a[i]]) 79 l[i] = max(l[i], vis[it]), vis[it] = i; 80 memset(vis, 0x3f, sizeof vis); 81 for (int i = n; i >= 1; --i) 82 for (auto it : fac[a[i]]) 83 r[i] = min(r[i], vis[it]), vis[it] = i; 84 //for (int i = 1; i <= n; ++i) printf("%d %d\n", l[i], r[i]); 85 //for (int i = 1; i <= n; ++i) for (int j = 0, len = fac[a[i]].size(); j < len; ++j) printf("%d%c", fac[a[i]][j], " \n"[j == len - 1]); 86 for (int i = 1; i <= n; ++i) 87 v[l[i]].emplace_back(r[i], i); 88 for (int qq = 1, l, r; qq <= q; ++qq) 89 { 90 scanf("%d%d", &l, &r); 91 qv[l].emplace_back(r, qq); 92 } 93 SEG::build(1, 1, n); 94 for (int i = 1; i <= n; ++i) 95 { 96 for (auto it : v[i - 1]) 97 SEG::update(1, 1, n, it.second, it.first - 1, 1); 98 for (auto it : qv[i]) 99 ans[it.second] = SEG::query(1, 1, n, it.first); 100 SEG::update(1, 1, n, i, r[i] - 1, -1); 101 } 102 for (int i = 1; i <= q; ++i) printf("%d\n", ans[i]); 103 } 104 return 0; 105 }
I:
Solved.
特判$n == 0 并且 m == 0 的情况$
其他情况下,因为$k >= |n - m| 先手的人只需要去掉石子使得两堆相同,然后跟着另一个人取就可以必胜$
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 ll n, m, k; 8 9 int main() 10 { 11 while(~scanf("%lld %lld %lld", &n, &m, &k)) 12 { 13 if(n == 0 || m == 0) puts("LAOZI CHUI SI NI!"); 14 else puts("HAI YOU SEI!"); 15 } 16 return 0; 17 }
J:
Solved.
考虑 末尾两位为00, 25, 50, 75四种状态
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int INF = 0x3f3f3f3f; 6 const int maxn = 1e5 + 10; 7 8 char str[maxn]; 9 10 int main() 11 { 12 while(~scanf("%s", str + 1)) 13 { 14 int ans = INF; 15 int len = strlen(str + 1); 16 17 //00 18 int tmp1 = -1, tmp2 = -1; 19 for(int i = len; i >= 1; --i) 20 { 21 if(str[i] == '0') 22 { 23 if(tmp1 == -1) tmp1 = len - i; 24 else if(tmp2 == -1) 25 { 26 tmp2 = len - i - 1; 27 break; 28 } 29 } 30 } 31 if(tmp1 != -1 && tmp2 != -1) ans = min(ans, tmp1 + tmp2); 32 33 //25 34 tmp1 = -1, tmp2 = -1; 35 for(int i = len; i >= 1; --i) 36 { 37 if(str[i] == '5') 38 { 39 if(tmp1 == -1) tmp1 = len - i; 40 } 41 if(str[i] == '2') 42 { 43 if(tmp2 == -1) tmp2 = len - i; 44 } 45 } 46 47 if(tmp1 != -1 && tmp2 != -1) 48 { 49 if(tmp1 < tmp2) 50 { 51 ans = min(ans, tmp1 + tmp2 - 1); 52 } 53 else 54 { 55 ans = min(ans, tmp1 + tmp2); 56 } 57 } 58 59 //50 60 tmp1 = -1, tmp2 = -1; 61 for(int i = len; i >= 1; --i) 62 { 63 if(str[i] == '0') 64 { 65 if(tmp1 == -1) tmp1 = len - i; 66 } 67 if(str[i] == '5') 68 { 69 if(tmp2 == -1) tmp2 = len - i; 70 } 71 } 72 73 if(tmp1 != -1 && tmp2 != -1) 74 { 75 if(tmp1 < tmp2) 76 { 77 ans = min(ans, tmp1 + tmp2 - 1); 78 } 79 else 80 { 81 ans = min(ans, tmp1 + tmp2); 82 } 83 } 84 //75 85 tmp1 = -1, tmp2 = -1; 86 for(int i = len; i >= 1; --i) 87 { 88 if(str[i] == '5') 89 { 90 if(tmp1 == -1) tmp1 = len - i; 91 } 92 if(str[i] == '7') 93 { 94 if(tmp2 == -1) tmp2 = len - i; 95 } 96 } 97 if(tmp1 != -1 && tmp2 != -1) 98 { 99 if(tmp1 < tmp2) 100 { 101 ans = min(ans, tmp1 + tmp2 - 1); 102 } 103 else 104 { 105 ans = min(ans, tmp1 + tmp2); 106 } 107 } 108 if(ans == INF) ans = -1; 109 printf("%d\n", ans); 110 } 111 return 0; 112 }