果然到了年末,智商余额不足,无限崩盘。
A New Year and Days
对着新年日历看一下,分类输出各种情况即可。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int main(){
int n;
cin>>n;
string q;
string str;
cin>>q;
cin>>str;
if(str=="week"){
if(n<=4||n==7){
cout<<52<<endl;
}else{
cout<<53<<endl;
}
}else{
if(n<=29){
cout<<12<<endl;
}else if(n<=30){
cout<<11<<endl;
}else{
cout<<7<<endl;
}
}
return 0;
}
B New Year and Old Property
把符合条件的数,用位运算预处理出来,然后计数。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
ll tab[5555];
int main(){
ll a,b;
cin>>a>>b;
int k=0;
for(ll i=2;i<61;i++){
ll tmp = (1LL<<i) - 1;
for(int j=0;j<i-1;j++){
ll m = 1LL<<j;
ll cur = tmp^m;
tab[k++]=cur;
}
}
ll ans = 0;
for(int i=0;i<k;i++){
if(tab[i]>= a && tab[i]<=b){
ans++;
}
}
cout<<ans<<endl;
return 0;
}
C New Year and Domino
利用前缀和,计算从左上角到每个格子有多少种放法。然后利用容斥原理拿4个矩形算一下,注意处理边界。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
char mp[555][555];
int cnt1[555][555];
int cnt2[555][555];
int ans[555][555];
int main(){
int h,w;
cin>>h>>w;
for(int i=1;i<=h;i++){
scanf("%s",mp[i]+1);
}
for(int i=2;i<=h;i++){
for(int j=1;j<=w;j++){
if(mp[i][j]=='.' && mp[i-1][j]=='.'){
cnt1[i][j]=cnt1[i-1][j]+1;
}else{
cnt1[i][j]=cnt1[i-1][j];
}
}
}
for(int i=2;i<=w;i++){
for(int j=1;j<=h;j++){
if(mp[j][i]=='.' && mp[j][i-1]=='.'){
cnt2[j][i]=cnt2[j][i-1]+1;
}else{
cnt2[j][i]=cnt2[j][i-1];
}
}
}
for(int i=1;i<=h;i++){
for(int j=2;j<=w;j++){
cnt1[i][j]+=cnt1[i][j-1];
}
}
for(int i=1;i<=w;i++){
for(int j=2;j<=h;j++){
cnt2[j][i]+=cnt2[j-1][i];
}
}
for(int i=1;i<=h;i++){
for(int j=1;j<=w;j++){
ans[i][j] = cnt1[i][j] + cnt2[i][j];
}
}
int q;
cin>>q;
while(q--){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int res = ans[x2][y2]-ans[x1-1][y2]-ans[x2][y1-1]+ans[x1-1][y1-1];
for(int i=x1;i<=x2;i++){
if(mp[i][y1]=='.'&&mp[i][y1-1]=='.')res--;
}
for(int i=y1;i<=y2;i++){
if(mp[x1][i]=='.'&&mp[x1-1][i]=='.')res--;
}
printf("%d\n",res);
}
return 0;
}
D New Year and Ancient Prophecy
dp。dp(i,j)表示考察到第i个字符,最后一段长度为j的方案数。dp(i,j)显然由dp(i-j,k)转移而来,k可以取若干个值,需要优化避免重复计算。另外由于后一个数需要严格大于前一个数,也就是涉及到最后两个数的大小比较,同样需要优化,原理类似。详见代码。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int mod = 1e9+7;
char num[5010];
int dp[5010][5010];
int sum[5010][5010];
pair<int,int> cmp[5010][5010];
int isLE(int a,int b,int c,int d){
int len = b-a+1;
int i=0;
if(a>0){
pair<int,int> pre = cmp[a-1][len];
if(pre.second){
if(pre.first){
cmp[a][len].first = pre.first;
cmp[a][len].second = pre.second - 1;
return pre.first;
}else{
i= len-1 ;
}
}else{
i=0;
}
}
for(;i<len;i++){
if(num[a+i]>num[c+i]){
cmp[a][len].first = 1;
cmp[a][len].second = i;
return 1;
}else if(num[a+i]<num[c+i]){
cmp[a][len].first = -1;
cmp[a][len].second = i;
return -1;
}
}
cmp[a][len].first = 0;
cmp[a][len].second = len-1;
return 0;
}
int main(){
int n;
cin>>n;
scanf("%s",num);
for(int i=0;i<n;i++){
for(int j=i;j>=1;j--){
if(num[j]=='0'){
dp[i][i-j+1]=0;
}else{
int start = j-1 - (i-j);
if(start<0)start=0;
if(j-1 - start == i-j){
if(isLE(start,j-1,j,i) >=0){
start++;
}
}
int tmp = sum[j-1][j-start];
dp[i][i-j+1]+=tmp;
dp[i][i-j+1]%=mod;
}
sum[i][i-j+1]=sum[i][i-j]+dp[i][i-j+1];
sum[i][i-j+1]%=mod;
}
dp[i][i+1]=1;
sum[i][i+1]=sum[i][i]+dp[i][i+1];
sum[i][i+1]%=mod;
}
int ans = 0;
for(int i=0;i<=n;i++){
ans+=dp[n-1][i];
ans%=mod;
}
cout<<ans<<endl;
return 0;
}
E New Year and Three Musketeers
二分答案+贪心判断答案是否可行。二分部分不用说,解肯定在[n/3,n]这个区间。难点在于贪心,需要给火枪手和敌人排序,按从大到小的顺序处理敌人。敌人分配原则是,优先分配给弱的火枪手打,优先分配给更少的火枪手打。还要注意一个坑,答案不是三个火枪手的最长工作时间,因为可能会有人被迫等待,所以还要考虑协同作战的时间是否超出。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int m[10];
int t[200010];
int n;
bool judge(int x){
int cnt[3]={0,0,0};
int share = 0;
for(int i=n-1;i>=0;i--){
if(t[i]<=m[0]){
if(cnt[0]<x){
cnt[0]++;
}else if(cnt[1]<x){
cnt[1]++;
}else if(cnt[2]<x){
cnt[2]++;
}else{
return 0;
}
}else if(t[i]<=m[1]){
if(cnt[1]<x){
cnt[1]++;
}else if(cnt[2]<x){
cnt[2]++;
}else{
return 0;
}
}else if(t[i]<=m[2]){
if(cnt[2]<x){
cnt[2]++;
}else if(t[i]<=m[0]+m[1] && cnt[0]<x && cnt[1]<x){
cnt[0]++;
cnt[1]++;
share++;
}else{
return 0;
}
}else if(t[i]<=m[0]+m[1]){
if(cnt[0]<x && cnt[1]<x){
cnt[0]++;
cnt[1]++;
share++;
}else if(cnt[0]<x && cnt[2]<x){
cnt[0]++;
cnt[2]++;
share++;
}else if(cnt[1]<x && cnt[2]<x){
cnt[1]++;
cnt[2]++;
share++;
}else{
return 0;
}
}else if(t[i]<=m[0]+m[2]){
if(cnt[0]<x && cnt[2]<x){
cnt[0]++;
cnt[2]++;
share++;
}else if(cnt[1]<x && cnt[2]<x){
cnt[1]++;
cnt[2]++;
share++;
}else{
return 0;
}
}else if(t[i]<=m[1]+m[2]){
if(cnt[1]<x && cnt[2]<x){
cnt[1]++;
cnt[2]++;
share++;
}else{
return 0;
}
}else{
if(cnt[0]<x && cnt[1]<x && cnt[2]<x){
cnt[0]++;
cnt[1]++;
cnt[2]++;
share++;
}else{
return 0;
}
}
}
if(share>x)return 0;
return 1;
}
int bs(int l,int r){
int mid;
int ans = 200000;
while(l<=r){
mid = (l+r)>>1;
if(judge(mid)){
r=mid-1;
ans = min(ans,mid);
}else{
l=mid+1;
}
}
return ans;
}
int main(){
cin>>n;
for(int i=0;i<3;i++){
cin>>m[i];
}
sort(m,m+3);
int sum = m[0]+m[1]+m[2];
for(int i=0;i<n;i++){
scanf("%d",&t[i]);
}
sort(t,t+n);
if(t[n-1]>sum){
cout<<-1<<endl;
}else{
int ans = bs(n/3,n);
cout<<ans<<endl;
}
return 0;
}