CF 1430 (Div.2)
$\text{A}$
依次暴力枚举 $3$ ,$5$ 的窗户个数,最后看能不能被 $7$ 整除即可
$code$ :
#include<cstdio> #include<cctype> inline int read(){ int r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } inline bool check(int n){ for(int i=0;i<=n;i+=5) if(!((n-i)%7))return true; return false; } inline void print(int n){ for(int i=0;i<=n;i+=5) if(!((n-i)%7)){ printf("%d %d",i/5,(n-i)/7); return; } } inline void work(){ int n=read(); for(int i=0;i<=n;i+=3) if(check(n-i)){ printf("%d ",i/3); print(n-i); puts(""); return; } puts("-1"); } int main(){ int t=read(); while(t--)work(); return 0; }
$\text{B}$
排个序以后答案就是前 $k+1$ 大的和
$code$ :
#include<cstdio> #include<cctype> #include<algorithm> using namespace std; #define maxn 202202 inline int read(){ int r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } int n,k,a[maxn]; long long ans; inline void work(){ ans=0; n=read(),k=read(); for(int i=1;i<=n;i++)a[i]=read(); sort(a+1,a+1+n); for(int i=0;i<=k;i++)ans+=a[n-i]; printf("%lld\n",ans); } int main(){ int t=read(); while(t--)work(); return 0; }
$\text{C}$
将 $n$ 与 $n-2$ 合并,造出一个 $n-1$ ,然后将两个 $n-1$ 合并为一个
然后就 $n-1$ 与 $n-3$ 合并,造出 $n-2$ ,再拿它与 $n-4$ 合并,一直搞下去就可以搞到 $2$ 了
然后要注意特判 $n=2$
$code$ :
#include<cstdio> #include<cctype> #define maxn 202202 inline int read(){ int r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } int n,a[maxn],ans[maxn][2]; inline void work(){ n=read(); if(n==2){ puts("2\n1 2"); return; } ans[1][0]=n-2,ans[1][1]=n; ans[2][0]=ans[2][1]=n-1; for(int i=n-1;i>=3;i--)ans[n-i+2][0]=i-2,ans[n-i+2][1]=i; printf("2\n"); for(int i=1;i<n;i++) printf("%d %d\n",ans[i][0],ans[i][1]); } int main(){ int t=read(); while(t--)work(); return 0; }
$\text{D}$
把每一段相同的缩成一个( $e.g. \ \ \ 1110011110->3241$ )
当删第 $i$ 号点的时候,分类讨论(其实可以写成一类):
- 若 $len_i = 1$ ( $len_i$ 即该段还剩下的大小)时,先往后找第一个 $j$ 满足 $len_j > 1$ ,然后让 $len_j--$ (即删掉这段中的一个),$i++$ ,若找不到满足条件的 $j$ ,则说明后面的段大小全都是 $1$ ,删了一个以后还会因为规则删掉一个,此时 $i+=2$
- 若 $len_i > 1$ 时,直接 $i++$ 即可
$code$ :
#include<cstdio> #include<cctype> #define maxn 202202 inline int read(){ int r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } int n,m,ans,len[maxn]; char s[maxn]; inline void work(){ ans=0; n=read(),m=0; scanf("%s",s+1); len[++m]=1; for(int i=2;i<=n;i++){ if(s[i]!=s[i-1])len[++m]=0; len[m]++; } int i=1,j=1; while(i<=m){ ans++; while(j<i)j++; while(j<=m&&len[j]<2)j++; if(j>m)i+=2; else i++,len[j]--; } printf("%d\n",ans); } int main(){ int t=read(); while(t--)work(); return 0; }
$\text{E}$
首先有一个结论,对于相同的字母,若我们给他们编号,那么 $reverse$ 完后相对顺序肯定不会变(因为没必要交换两个相同的)
所以我们可以算出每个位置最后所对应的位置 $p_i$ ,又因为每次交换相邻两个,且要把 $p$ 变成 $1,2,3,...,n$ ,可以想到最小次数就是逆序对个数,求一下就好了
$code$ :
#include<cstdio> #include<cctype> #define maxn 202202 #define lowbit(k) (k&(-k)) inline int read(){ int r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } char s[maxn]; long long ans; int n,s_w[33],p[maxn],c[maxn],w[33][maxn]; inline void add(int k){ for(;k<=n;k+=lowbit(k))c[k]++; } inline int sum(int k){ int s=0; for(;k;k-=lowbit(k))s+=c[k]; return s; } int main(){ n=read(); scanf("%s",s+1); for(int i=1;i<=n;i++){ int num=s[i]-'a'+1; w[num][++s_w[num]]=i; } for(int i=1;i<=26;i++) for(int j=1;j<=s_w[i];j++) p[w[i][j]]=n-w[i][s_w[i]-j+1]+1; for(int i=1;i<=n;i++){ add(p[i]); ans+=i-sum(p[i]); } printf("%lld\n",ans); return 0; }
$\text{F}$
好题, $DP$ 和贪心都可以, $DP$ 似乎是 $O(n^2)$ 甚至 $O(n^2logn)$ ,可以通过本题,不过较为复杂,这里考虑贪心。
很明显,最优的应该是能不换弹就不换,但是对于当前一波,后面的都会影响到这一波的决策,所以考虑从后往前先预处理一下 $need_i$ 表示原本弹夹里的子弹至少要多少才能打完第 $i-n$ 波
然后预处理完以后能不换就不换,每次弹夹里剩余的子弹经过一波以后就是 $bullet=k-(a_i-bullet)%k$ ,但要考虑一种特殊情况:当 $bullet > a_i $ 时, 直接 $bullet-=a_i$ 即可(不过总结起来也可以写成 $bullet=(k-(a_i-bullet)%k))%k$ ,这里利用了一下 C++ 取模的性质)
$code$ :
#include<cstdio> #include<cctype> #define maxn 2222 #define lowbit(k) (k&(-k)) inline int read(){ int r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } inline long long max(long long a,long long b){ return a>b?a:b; } int n,k,l[maxn],r[maxn],a[maxn],need[maxn]; long long ans; int main(){ n=read(),k=read(); for(int i=1;i<=n;i++) l[i]=read(),r[i]=read(),a[i]=read(); for(int i=n;i>=1;i--){ int ned=a[i]; if(r[i]==l[i+1])ned+=need[i+1]; if(ned>1ll*(r[i]-l[i]+1)*k)return puts("-1"),0; need[i]=max(ned-1ll*(r[i]-l[i])*k,0); } int had=0; for(int i=1;i<=n;i++){ if(had<need[i]){ ans+=had; had=k; } ans+=a[i]; had=had<a[i]?k-(a[i]-had)%k:had-a[i]; } printf("%lld\n",ans); return 0; }