比赛链接:
A——Prison Break
题意
给你一个n*m的矩阵以及在矩阵上的一个点,求这个点到这个矩阵四个角的最远曼哈顿距离。
题解
模拟取最大值即可,答案即为max(n-r,r-1)+max(m-c,c-1)。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } void solve(){ ll n,m,r,c;scl(n);scl(m);scl(r);scl(c); ll res1=max(abs(n-r)+abs(m-c),abs(r-1)+abs(c-1)); ll res2=max(abs(n-r)+abs(c-1),abs(r-1)+abs(m-c)); printf("%lld\n",max(res1,res2)); } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else // freopen("in.txt", "r", stdin); // debug = 1; #endif time_t beg, end; if(debug) beg = clock(); int T=read(); while(T--){ solve(); } if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } return 0; }
B——Repainting Street
题意
给你一个长度为n的序列a,a[i]即表示第i位的颜色为a[i],你可以进行一种操作:把[i,i+k-1]位的序列变成一个颜色,让你求出把这个序列变成全一样颜色的最小操作数。
题解
这个题的关键在于颜色数很少,最大为100,因此我们首先暴力枚举序列最后的颜色,然后我们如何最小化操作数,不难想到一个贪心的策略,首先把所有和最终颜色不一样的位置按顺序存入一个vector里面,然后我们遍历vector,不断的执行这两种操作:1.把从最小位置pos开始到pos+k-1位置中颜色不同的变成一个颜色,2.更新最小位置. 中间记录一下答案就可以了。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e6+7; int c[N]; int cnt[107]; void solve(){ int n=read(),k=read(); rp(i,1,n) c[i]=read(); rp(i,1,100) cnt[i]=0; rp(i,1,n) cnt[c[i]]++; int ans=1e5+7; rp(i,1,100){ if(cnt[i]==0) continue; int id=i; vector<int> v;v.clear(); rp(j,1,n) if(c[j]!=id) v.push_back(j); if(v.size()==0){ ans=min(ans,0); continue; } int len=v.size(); int cur=v[0]; int res=0; int j=0; while(j<=len-1){ while(j+1<=len-1&&v[j+1]-cur+1<=k) j++; res++; if(j==len-1) break; j++; cur=v[j]; } ans=min(ans,res); } printf("%d\n",ans); } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); debug = 1; #endif time_t beg, end; if(debug) beg = clock(); int T=read(); while(T--){ solve(); } if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } return 0; }
C——Bouncing Ball
题意
给你一个长度为n的01字符串s,以及一个基点p和周期k,每次取第p位,第p+k位,第p+2k位.....,形成一个新的字符串ss。
你可以进行两种操作:1.把第一位删掉,代价为x(注意ss会变)。2.把ss中的0变成1,代价为y。
让你求出把ss全部变成1的最小代价。
题解
不难发现第一种操作的实际意义就是把p往后挪一位,因此我们可以遍历一遍数组统计一下从p开始周期为k的代价(即0的个数),记录到b[(i-p)%k]。
然后枚举它的基点i在[p,n]范围内,维护一下最小答案(即 偏移多少位的代价 (i-p)*x + 0的个数*y )行了。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e5+7; char s[N]; int cnt[N]; void solve(){ int n=read(),p=read(),k=read(); scanf("%s",s+1); int x=read(),y=read(); rp(i,0,k-1) cnt[i]=0; rp(i,1,n) if(i>=p) cnt[(i-p)%k]+=(s[i]=='0'); ll ans=1ll*n*max(x,y); rp(j,0,(n-p)/k){ rp(i,0,k-1){ if(j*k+i+p>n) break; int tt=cnt[i]; if(s[j*k+i+p]=='0') cnt[i]--; ans=min(ans,1ll*tt*x+1ll*y*(j*k+i)); } } printf("%lld\n",ans); } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); debug = 1; #endif time_t beg, end; if(debug) beg = clock(); int T=read(); while(T--) solve(); if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } return 0; }
D——XOR-gun
题意
给你一个长度为n不严格单调递增的序列a,我们有一种操作:把相邻的两个数a[i]和a[i+1]取出,放进去这两个数异或之后的答案val到第i位,后面往前移。
让你求出把这个序列变成递减序列的最小操作数。
题解
首先需要知道一个结论:任意三个相邻数,如果它们的最高位一样,那么我们可以取最右边相邻两位数异或,异或后的答案肯定比最左边的数小,即符合条件,代价为1。因为数据范围最大为1e9<2^30,且需要保证不严格递增性质,所以当数组长度大于60时,答案肯定为1(考虑极端情况,即1(1),1(1),2(10),2(10),8(100),8(100),16(1000),16(1000)......2^30(1000....00),这个序列最大长度就是60),这样数据范围就很小了,我们可以直接暴力枚举就行了,n^3和n^4的都能过。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e5+7; ll a[N]; ll sum[N]; void solve(){ int n=read(); sum[0]=0; rp(i,1,n){ scl(a[i]); sum[i]=(sum[i-1]^a[i]); } if(n>60){ puts("1"); return ; } int ans=n+1; rp(l,1,n-1){ rp(r,l+1,n){ rp(k,r+1,n){ if((sum[r]^sum[l-1])>(sum[k]^sum[r])){ ans=min(ans,r-l+k-r-1); } } rp(k,1,l-1){ if((sum[r]^sum[l-1])<(sum[l-1]^sum[k-1])){ ans=min(ans,r-l+l-1-k); } } } } if(ans==n+1) cout<<-1<<endl; else cout<<ans<<endl; } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); debug = 1; #endif time_t beg, end; if(debug) beg = clock(); solve(); if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } return 0; }
E——New Game Plus!
题意
(来自https://blog.csdn.net/qq_45458915/article/details/110388504)
给出一个长度为 n 的序列a,需要自己定义一种顺序去遍历序列,每次需要维护答案:
- ans += sum
- sum += a[ i ]
有 k 次机会可以将 sum 清零,问如何遍历可以使得最后的 ans 最大
解法一
首先对于长度为L的序列b,答案就是b[1]*(L-1)+b[2]*(L-2)+......+b[L]*0。对于正数根据贪心的思想不难发现答案就是从大到小后的顺序,
当sum变成负数时,本质还是一样的,只不过因为我们有k次机会可以清0,那么我们就可以把序列分成k+1段子序列(互相独立),类似于高中数学中的挡板思想,然后我们把第一个变成负数的sum和后面的序列放进一个vector里面,从小到大依次放进每一段序列的倒数第一个(b[L]*0),当k+1段的倒数第一个放满后再放倒数第二个,按照这个顺序模拟到所有序列放完,最后对每一段序列求一下答案,再累加一下就行了。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 1e5+7; void solve(){ int n=read(),k=read(); vector<int> v1,v2; rp(i,1,n){ int x=read(); if(x>=0) v1.push_back(x); else v2.push_back(x); } sort(v1.begin(),v1.end(),greater<int>()); ll cur=0,ans=0; for(auto val:v1){ ans+=cur; cur+=val; } sort(v2.begin(),v2.end(),greater<int>()); vector<int> v;int len=v2.size(); rp(i,0,len-1){ if(cur<0){ v.push_back(cur); while(i<=len-1){ v.push_back(v2[i]); i++; } } else{ ans+=cur; cur+=v2[i]; } } // for(auto val:v) cout<<val<<" "; // cout<<endl; k++; sort(v.begin(),v.end()); len=v.size(); rp(i,0,len-1) ans+=1ll*v[i]*(i/k); cout<<ans<<endl; } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); debug = 1; #endif time_t beg, end; if(debug) beg = clock(); solve(); if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } return 0; }
解法二
比较难想的贪心,根据解法一,最终我们是要把序列分成k+1段的,因此我们把数从大到小排序后,每次都把当前数加到和最大的那个组就行了。
代码
#include <bits/stdc++.h> #define PI atan(1.0)*4 #define rp(i,s,t) for (register int i = (s); i <= (t); i++) #define RP(i,t,s) for (register int i = (t); i >= (s); i--) #define sc(x) scanf("%d",&x) #define scl(x) scanf("%lld",&x) #define ll long long #define ull unsigned long long #define mst(a,b) memset(a,b,sizeof(a)) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define pii pair<int,int> #define pll pair<ll,ll> #define pil pair<int,ll> #define m_p make_pair #define p_b push_back #define ins insert #define era erase #define INF 0x3f3f3f3f #define LINF 0x3f3f3f3f3f3f3f3f #define dg if(debug) #define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"; using namespace std; int debug = 0; ll gcd(ll a,ll b){ return b?gcd(b,a%b):a; } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } inline int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; } const int N = 5e5+7; int a[N]; void solve(){ int n=read(),k=read(); rp(i,1,n) a[i]=read(); sort(a+1,a+n+1,greater<ll>()); priority_queue<ll> q; rp(i,1,k+1) q.push(0ll); ll ans=0; rp(i,1,n){ ans+=q.top(); // cout<<q.top()<<endl; ll tmp=q.top()+a[i]; q.pop(); q.push(tmp); } cout<<ans<<endl; } int main(){ //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); #ifdef ONLINE_JUDGE #else freopen("in.txt", "r", stdin); debug = 1; #endif time_t beg, end; if(debug) beg = clock(); solve(); if(debug) { end = clock(); printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC); } return 0; }