題目鏈接<-請點擊
題目
A.不等式
將不等式的邊界值存起來,然後依次進行判斷即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200 + 10;
typedef long long LL;
int a[maxn], b[maxn];
string op[maxn];
int main()
{
int n;
scanf("%d",&n);
string x;
for(int i = 1; i <= n; i++)
{
cin >> x;
cin >> op[i];
scanf("%d", &a[i]);
//cout << x << op[i] << a[i] << endl;
if(op[i] == "<") b[i] = a[i] - 1;
else if(op[i] == ">") b[i] = a[i] + 1;
else b[i] = a[i];
}
int ans = 0;
for(int i = 1; i <= n; i++)
{
int res = 0;
for(int j = 1; j <= n; j++)
{
if(op[j] == "=" && b[i] == a[j]) res ++;
else if(op[j] == "<" && b[i] < a[j]) res ++;
else if(op[j] == ">" && b[i] > a[j]) res ++;
else if(op[j] == "<=" && b[i] <= a[j]) res++;
else if(op[j] == ">=" && b[i] >= a[j]) res++;
}
ans = max(ans, res);
}
printf("%d\n",ans);
return 0;
}
B. 1 的個數最多的整數
首先將a,b 都化爲二進制形式,然後對於a的二進制形式從低位向高位進行遍歷,如果該位爲0則考慮變爲1後是否會大於b,不會大於b則將其變爲1後繼續判斷,否則停止遍歷。原理:如果高位可變爲1則低位更加能變成1。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 10;
typedef long long LL;
LL a,b;
string change(LL x)
{
string res;
while(x)
{
res += (x%2) + '0';
x >>= 1;
}
return res;
}
int main()
{
int cas = 0,T;
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld",&a,&b);
string sa,sb;
sa = change(a);
sb = change(b);
// cout << sa << endl;
// cout << sb << endl;
LL tmp = 1;
for(int i = 0; i < sb.size(); i++, tmp <<= 1)
if((i >= sa.size() || sa[i] == '0') && a + tmp <= b)
a += tmp;
printf("Case %d: %lld\n",++cas,a);
}
return 0;
}
C. 打印
線性DP, 通過插入、刪除、複製三個操作進行狀態轉移。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7 + 10;
typedef long long LL;
LL dp[maxn];
int main()
{
int n,x,y;
scanf("%d%d%d", &n, &x, &y);
for(int i = 1; i <= n; i++)
if(i % 2 == 0)
dp[i] = min(dp[i-1] + x, dp[i/2] + y);
else dp[i] = min(dp[i-1] + x, min(dp[(i-1)/2]+y+x, dp[(i+1)/2]+y+x));
printf("%lld\n",dp[n]);
return 0;
}
D. 十億分考
直接暴力化分數會WA或者TLE, 考慮通過連分數來進行,小數化連分數、連分數再化分數。
連分數講解<-請點擊
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200 + 10;
typedef long long LL;
double n;
vector<int>cnt;
LL gcd(LL a, LL b)
{
return b == 0? a: gcd(b, a%b);
}
double cal()
{
double res = 0;
for(int i = cnt.size()-1; i >= 0; i--)
{
res += cnt[i];
res = 1/res;
}
return res;
}
int main()
{
double x;
cin >> n;
x = n;
double y = 0;
while(fabs(n-cal()) > 0.5*1e-15)
{
x = 1/x;
cnt.push_back(int(x));
x -= int(x);
}
// for(int i = 0; i < cnt.size(); i++)
// cout << cnt[i] << endl;
LL p = 0,q = 1;
for(int i = cnt.size()-1; i >= 0; i--)
{
p += q*cnt[i];
swap(p,q);
}
// cout << p << q << endl;
LL g = gcd(p,q);
printf("%lld %lld\n",p/g, q/g);
// printf("%.15f\n",1.0*p/q);
return 0;
}
E. 有錢人買鑽石
使用DFS加貪心,DFS的每一層爲一種硬幣,因爲要總重量(數量)最大,所以從小面額到大面額DFS。DFS從上一層轉移到下一層時,使用的本層硬幣數爲[low,high], high = min(所需要的, 所有的)的數量,low = max(0,high - 5); high 很容易理解,很合理,而low爲什麼取high-25 ? 最大面額爲25, 當前面的某一個面額裝換成後面的面額時,最多消耗25個小面額即可。
(如果前面懂了,後面可以不用看了)可以分兩個情況來思考一下,一個是如果high = 所有的,說明當前面額不足,所以可以讓後面的來補缺口,這個缺口一定視爲x+y*大面額,0<=x<=25。如果high = 所需要的,說明當前充足,按理說可以取了所需要的到下一步, 但是可能會出現這樣一種情況,當前剩餘25,現在面額爲10的有三張,爲25的有一張,先考慮面額爲10的,如果取了兩張20的就會導致Impossible。
#include<bits/stdc++.h>
using namespace std;
int p, v[4], c[4] = {1 ,5, 10, 25};
int ans = -1;
bool dfs(int id, int num, int sum)
{
// printf("%d %d %d\n",id, num, sum);
if(sum == p) {ans = num; return true;}
if(id >= 4 || sum > p) return false;
int high = min((p-sum)/c[id], v[id]);
int low = max(0,high-25);
for(int i = high; i >= low; i--)
if(dfs(id+1, num + i, sum + i * c[id])) return true;
return false;
}
int main()
{
scanf("%d%d%d%d%d",&p, &v[0], &v[1], &v[2], &v[3]);
if(dfs(0,0,0)) printf("%d\n", ans);
else printf("Impossible\n");
return 0;
}
F. 送分題
離線查詢,使用莫隊算法可解。莫隊算法講解 <-請點擊
因爲數據範圍爲5e5, 使用莫隊nsqrt(n) 差不多剛好,和bzoj 1878 HH的項鍊 大同小異。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+10;
int n,m,block;
int a[maxn],b[maxn],l[maxn],r[maxn],num[maxn],ans[maxn];
int cl = 1,cr=0,cnt = 0;
map<int,int>mp;
bool cmp(int x, int y)
{
return (l[x]/block) ^ (l[y]/block) ? l[x] < l[y] : r[x] < r[y];
}
void add(int x)
{
if(num[a[x]] == 2) cnt--;
if(++num[a[x]] == 2) cnt++;
}
void del(int x)
{
if(num[a[x]] == 2) cnt--;
if(--num[a[x]] == 2) cnt++;
}
int main()
{
scanf("%d%d",&n, &m);
block = sqrt(n);
int tot = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
if(mp.count(a[i]) == 0) mp[a[i]] = tot++;
a[i] = mp[a[i]];
}
memset(num,0,sizeof(num));
// for(int i = 1; i <= n; i++) printf("%d ",a[i]);
// printf("\n");
for(int i = 0; i < m; i++) {scanf("%d%d",&l[i],&r[i]);b[i] = i;}
sort(b,b+m,cmp);
for(int i = 0; i < m; i++)
{
while(cl < l[b[i]]) del(cl++);
while(cl > l[b[i]]) add(--cl);
while(cr < r[b[i]]) add(++cr);
while(cr > r[b[i]]) del(cr--);
// printf("\n");
// printf("%d %d %d %d\n",l[b[i]],r[b[i]],cl,cr);
// for(int j = 0; j < tot; j++) printf("%d ",num[j]);
// printf("\n");
ans[b[i]] = cnt;
}
for(int i = 0; i < m; i++) printf("%d\n",ans[i]);
return 0;
}