A:签到题
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 1e5+5; const int M = 2e5+5; const LL Mod = 199999; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){/*freopen("data1.in","r",stdin); freopen("data1.out","w",stdout);*/} int main() { int ca;ca = read(); while(ca--) { int a,b;a = read(),b = read(); if(a > b) swap(a,b); int dis = b-a; int ma = dis/10; if(ma*10 == dis) printf("%d ",ma); else printf("%d ",ma+1); } //system("pause"); }
B:这里假设了一下减去个值为t0,然后求出的乘积为一个开口向下的二次函数。
那么要最小化乘积,显然是在两边,也就是极限的两个位置,那么就是先让x尽可能小,然后让y尽可能小,求一下两者之间的最小即可
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 1e5+5; const int M = 2e5+5; const LL Mod = 199999; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){/*freopen("data1.in","r",stdin); freopen("data1.out","w",stdout);*/} LL slove(LL a,LL b,LL x,LL y,LL n) { LL dis1 = min(n,a-x); a -= dis1; n -= dis1; LL dis2 = min(n,b-y); b -= dis2; return a*b; } int main() { int ca;ca = read(); while(ca--) { LL a,b,x,y,n; a = read(),b = read(),x = read(),y = read(),n = read(); LL ans = slove(a,b,x,y,n); ans = min(ans,slove(b,a,y,x,n)); printf("%lld ",ans); } // system("pause"); }
C:可以发现,在给定的两个值中间能插入越多的数,差距就会越大,然后剩余要插的就会越少。
那么我们就去找可以在中间插入多少,然后就找到了差距,然后先向小的方向插剩余的,然后再插大的方向
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 1e5+5; const int M = 2e5+5; const LL Mod = 199999; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){/*freopen("data1.in","r",stdin); freopen("data1.out","w",stdout);*/} int main() { int ca;ca = read(); while(ca--) { int n,x,y;n = read(),x = read(),y = read(); n -= 2; vector<int> ans; ans.push_back(x); if(n == 0) ans.push_back(y); else { int dis = y-x,ma = 0; int m = sqrt(dis); for(rg int i = 1;i <= dis-1;++i) { if(dis%i == 0 && dis/i-1 <= n) { ma = i; break; } } if(ma == 0) { ans.push_back(y); int dis = y-x; for(rg int i = x-dis;i > 0 && n > 0;i -= dis) ans.insert(ans.begin(),i),n--; for(rg int i = y+dis;n > 0;i += dis) ans.push_back(i),n--; } else { int dis = ma; for(rg int i = x+dis;i < y;i += dis) ans.push_back(i),n--; for(rg int i = x-dis;i > 0 && n > 0;i -= dis) ans.insert(ans.begin(),i),n--; for(rg int i = y+dis;n > 0;i += dis) ans.push_back(i),n--; ans.push_back(y); } } for(rg int i = 0;i < ans.size();++i) printf("%d%c",ans[i],i == ans.size()-1 ? ' ' : ' '); } //system("pause"); }
D:注意题目,满足小于等于即可。
模拟进制转化,从最小位开始向上进位,每次进位后都满足减去部分值。
当<=时就退出,注意中途记录答案值,不然最后的话,要把值进完再找最后的值相减,很麻烦。
证明一下为什么这样肯定是最小。
因为我们是不断从小开始进位,数值是在不断增大,但是现在最低位都为0了,如果去增加最低位,显然不会对答案产生贡献,那么,就满足增加最高位之后,第一次满足的肯定是最小。(有点口胡~)
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 1e5+5; const int M = 2e5+5; const LL Mod = 199999; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){/*freopen("data1.in","r",stdin); freopen("data1.out","w",stdout);*/} int a[25],len; int Get_dig() { int sum = 0; for(rg int i = 1;i <= len;++i) sum += a[i]; return sum; } int main() { int ca;ca = read(); while(ca--) { memset(a,0,sizeof(a)); string s;cin >> s; int ss;ss = read(); len = s.size(); for(rg int i = 0;i < len;++i) a[len-i] = s[i]-'0'; int dig = Get_dig(); if(dig <= ss) printf("0 "); else { LL ans = 0,ma = 1; for(rg int i = 1;i <= len;++i,ma *= 10) { ans += (10-a[i])*ma; a[i] = 0; a[i+1]++; if(Get_dig() <= ss) break; } printf("%lld ",ans); } } // system("pause"); }
E:这题我感觉不是很难,一发就过了。
题意很显然,我们先排序去重。map记录下每个位置重复的个数。
然后我们可以去枚举第一个放的线段,显然我们枚举的是左边界,并且显然这个左边界在存在的点上更优。
第一条显然的覆盖点数我们可以二分+前缀和求出。
然后我们再去枚举第二个放的线段,显然这个线段的左起点应该在当前区间右边界外更优。
那么此时,我们枚举两个的复杂度为n^2。这显然会T。
但是,我们可以先处理出dp[i]表示i~n里选择某个点为起点的最优覆盖长度的最大值。
然后枚举第一个线段时,对于第二个线段就可以高效求出了。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 2e5+5; const int M = 2e5+5; const LL Mod = 1e9+7; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){/*freopen("data1.in","r",stdin); freopen("data1.out","w",stdout);*/} int x[N],y[N]; LL sum[N],dp[N];//dp[i]-i~n的最优价值 int main() { int ca;ca = read(); while(ca--) { int n,k;n = read(),k = read(); unordered_map<int,int> mp; for(rg int i = 1;i <= n;++i) x[i] = read(),mp[x[i]]++; for(rg int i = 1;i <= n;++i) y[i] = read(); sort(x+1,x+n+1); int len = unique(x+1,x+n+1)-x-1; sum[0] = 0; for(rg int i = 1;i <= len;++i) sum[i] = sum[i-1]+mp[x[i]]; int mx = x[len]; dp[len+1] = 0; for(rg int i = len;i >= 1;--i) { LL pos = x[i]+k,ma; if(pos >= mx) ma = sum[len]-sum[i-1]; else { int pt = upper_bound(x+1,x+len+1,pos)-x; ma = sum[pt-1]-sum[i-1]; } dp[i] = max(dp[i+1],ma); } LL ans = 0; for(rg int i = 1;i <= len;++i) { int pos = x[i]+k; LL tmp1,tmp2; if(pos >= mx) { tmp1 = sum[len]-sum[i-1]; tmp2 = 0; } else { int pt = upper_bound(x+1,x+len+1,pos)-x; tmp1 = sum[pt-1]-sum[i-1]; tmp2 = dp[pt]; } ans = max(ans,tmp1+tmp2); } printf("%lld ",ans); } // system("pause"); }
F:第一眼就感觉是dp,无从下手。太菜了太菜了~~
注意t只有两个字符。
定义dp[i][j][k]表示前i个位置,变换了j个数,k个t0的最多方案数。
注意的是要判断两个字符相同时的影响。转移的话就三种,si不变,si变t0,si变t1。注意这里的方案都算的是到i位置的方案数。
对于i~n的方案数都还未计算,然后可以发现,到了n位置,n+1位置可能才会记录到n位置的方案数,所以最后也要计算到n+1位置。
// Author: levil #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<string,int> pii; const int N = 2e5+5; const int M = 2e5+5; const LL Mod = 1e9+7; #define rg register #define pi acos(-1) #define INF 1e9 #define CT0 cin.tie(0),cout.tie(0) #define IO ios::sync_with_stdio(false) #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ inline LL read(){ LL x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){/*freopen("data1.in","r",stdin); freopen("data1.out","w",stdout);*/} LL dp[205][205][205];//dp[i][j][k]-前i个位置更改了j个字符,t0的数量为k时的方案数 int main() { int n,k;n = read(),k = read(); string s;cin >> s; string t;cin >> t; char t0 = t[0],t1 = t[1]; memset(dp,-0x3f,sizeof(dp)); LL low = dp[0][0][0]; LL ans = 0; dp[1][0][0] = 0; for(rg int i = 1;i <= n;++i) { char ch = s[i-1]; for(rg int j = 0;j <= k;++j) { for(rg int z = 0;z <= n;++z) { if(dp[i][j][z] == low) continue; // printf("i is %d j is %d z is %d ",i,j,z); int num1 = (ch == t0); int num2 = (ch == t1); dp[i+1][j][z+num1] = max(dp[i+1][j][z+num1],dp[i][j][z]+num2*z);//不变si if(j < k)//一定要<,当=时无法再变换 { int same = (t0 == t1); dp[i+1][j+1][z+1] = max(dp[i+1][j+1][z+1],dp[i][j][z]+same*z);//变成t1 dp[i+1][j+1][z+same] = max(dp[i+1][j+1][z+same],dp[i][j][z]+z);//变成t1 } } } } for(rg int i = 1;i <= n+1;++i) for(rg int j = 0;j <= n;++j) for(rg int k = 0;k <= n;++k) ans = max(ans,dp[i][j][k]); printf("%lld ",ans); //system("pause"); }