A:http://codeforces.com/contest/1393/problem/A
解析:
猜的,没看懂题意。
#include <bits/stdc++.h> #include<stdlib.h> using namespace std; typedef long long ll; const int N=100010; int a[N],b[N],f[N*2]; bool c[N*2]; map<int,int> m; int find(int x) { if(f[x]!=x) f[x]=find(f[x]); return f[x]; } int main() { int t; cin>>t; while(t--) { ll n; cin>>n; cout<<n/2+1<<endl; } }
B:http://codeforces.com/contest/1393/problem/B
题意:
给出N个长度已给出的木板,接下来进行增加/减少对应长度木板的操作(减少的前提是对应长度存在)
问是否能组成一个正方形+一个长方形(可为正方形)
解析:
记录两个值,出现次数为4的有几个,出现次数为2的有几个。
出现次数为4,记录后马上清0。
本解法达到了这么一个目的:
比如:1 1 1 1 1 1 2 2
f2=3
f4=1
f4中包含了一个f2。
具体的看注释吧:
#include<iostream> #include<map> #include<set> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1e5+10; int a[maxn]; int main() { int n; cin>>n; int f2=0,f4=0; map<int,int>m; for(int i=1;i<=n;i++) { int g; cin>>g; m[g]++; if(m[g]==4) f4++,m[g]=0; if(m[g]==2) f2++; //所以f4里包含了一个f2,最后要特殊处理 } int q; cin>>q; while(q--) { char ch; int h; cin>>ch>>h; if(ch=='+') { m[h]++; if(m[h]==4) f4++,m[h]=0; if(m[h]==2) f2++; } else { m[h]--; if(m[h]==-1) //-1了,说明这个m[h]之前为0,那么之前就是为4,所以-1后,变成3即可。 m[h]=3; if(m[h]==3) //既然变成了3,说明之前为4,那么f4-- f4--; if(m[h]==1) //之前为2,所以f2-- f2--; } if(f4>=2||(f4==1&&f2>=3)) //f4中包含了一个f2,所以f2需要多一个才能组成长方形 cout<<"YES"<<endl; else cout<<"NO"<<endl; } }
C:http://codeforces.com/contest/1393/problem/C
构造+贪心+公式
题意:
n个蛋糕,编号对应所属类型。怎么样排序,使得相同类型蛋糕的间隔的最小值最大。求这个值。
解析:
很明显,贪心,要想最小值最大,那么同类型之间要尽可能地插入其他类型蛋糕,而且在这些间隔中,要平均地插。
那么首要起决定性作用的,是出现次数最多的那个。
比如:
1 1 1 1 2 3 4
有:1 2 1 3 1 4 1
如果出现最多次数的类型有多个:
1 1 1 1 2 2 2 2 3 4 5 6 7 8
有:1 2 (3,4) 1 2 (5,6) 1 2 (7,8) 1 2
既,出现最多的这些类型,每个取一个依次放,做为隔板,其他的平均往里插即可。
那么根据此,可以得到公式:
maxx为出现次数最多的次数,num为几个同maxx
(num-1)+(n-num*maxx)/(maxx-1)
#include<iostream> #include<cstring> #include<algorithm> #include<stack> #include<map> #include<map> using namespace std; typedef long long ll; const int mod=60; const int maxn=1e5+7; int l[maxn],r[maxn]; int a[maxn]; int b[8*maxn]; int vis[maxn]; ll c[maxn],d[maxn]; int pos[maxn]; int main() { int t; cin>>t; while(t--) { int n; cin>>n; // memset(vis,0,sizeof(vis)); int maxx=0; map<int,int>m; for(int i=1;i<=n;i++) { int x; cin>>x; m[x]++; maxx=max(maxx,m[x]); } int num=0; for(int i=1;i<maxn;i++) { if(m[i]==maxx) { num++; } } cout<<num-1+(n-num*maxx)/(maxx-1)<<endl; } }
D:https://codeforces.com/contest/1393/problem/D
题意:
问n*m的矩阵中,有多少个如图菱形(单个字符也算)
解析:参考自:
定义dp[i][j],表示以(i,j)为最底端的菱形的个数
对于(i-1,j)这个点,已经被(i-2,j)所维护,不必再看。
以(i,j)为底的菱形,它的扩大取决于标注的另外三个点,能扩多大,又取决于这三个点至少能够延伸多少,所以要对它们取min()
转移方程:
dp[i][j]=1;
dp[i][j]+=min(min(dp[i-1][j-1],dp[i-1][j+1]),dp[i-2][j]);
#include<iostream> #include<cstring> #include<algorithm> #include<stack> #include<map> #include<map> using namespace std; typedef long long ll; const int mod=60; const int maxn=1e5+7; int l[maxn],r[maxn]; int a[maxn]; int b[8*maxn]; int vis[maxn]; ll c[maxn],d[maxn]; int pos[maxn]; const int maxn2=2e3+10; char mp[maxn2][maxn2]; int dp[maxn2][maxn2]; int main() { int n,m; cin>>n>>m; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) cin>>mp[i][j]; } int sum=0; for(int i=0;i<n;i++) { for(int j=0;j<m;j++) { dp[i][j]=1; if(i>=2&&j>=1&&j<m-1&&mp[i][j]==mp[i-1][j-1]&&mp[i][j]==mp[i-1][j+1]&&mp[i][j]==mp[i-2][j]&&mp[i][j]==mp[i-1][j]) { dp[i][j]+=min(min(dp[i-1][j-1],dp[i-1][j+1]),dp[i-2][j]); }sum+=dp[i][j]; // cout<<dp[i][j]<<' '; } } cout<<sum<<endl; }