1003 Simple Set Problem
双指针的思想,双端队列
先从小到大排个序
一个一个放到双端队列里,一边放一边维护集合个数为k个
利用滑动窗口,当滑动窗口中集合个数为k时,只需算出滑动窗口最后一个数减去第一个数,然后每次取min就行了
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
typedef pair<int,int>PII;
const int N=1e6+10;
typedef pair<int,int>PII;
typedef long long ll;
int k,c;
int cnt[N];
void solve()
{
cin>>k;
int n=0;
vector<PII>ans;
for(int i=0;i<k;i++) cnt[i]=0;
for(int i=0;i<k;i++){
cin>>c;
n+=c;
while(c--){
int x;
cin>>x;
ans.push_back({x,i});
}
}
sort(ans.begin(),ans.end());
int sum=0;
int res=2e9;
deque<int>q;
for(int i=0;i<n;i++){
if(!cnt[ans[i].second]) sum++;
q.push_back(i);
cnt[ans[i].second]++;
if(sum<k) continue;
while(cnt[ans[q.front()].second]>1){
cnt[ans[q.front()].second]--;
q.pop_front();
}
res=min(res,ans[q.back()].first-ans[q.front()].first);
}
cout<<res<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}
1006 PSO
两两组合
期望=所有组合的边数/组合数
组合数为中心节点与其它n-1个节点组合+在其它n-1个节点中选2个的组合(cnt)
所有组合的边数为n-1+2*cnt
当n大于2时,最大值均为2
另外,当n为2时,还需要特判,最大值为1
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
//typedef pair<int,int>PII;
typedef long long ll;
ll n;
ll C2(ll x){
return x*(x-1)/2;
}
void solve()
{
cin>>n;
double res=((double)2*C2(n-1)+n-1)/(C2(n-1)+n-1);
printf("%.9lf ",res);
if(n==2) printf("%.9lf\n",1.0);
else printf("%.9lf\n",2.0);
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}
1010 Kong Ming Qi
n*m和m*n是等价的,所以统一换成n小m大
当n为1时,答案明显为(m+1)/2
然后由一个基本图形(图1),可以吃掉连续三个棋子(如图4)
所以当n不是1时,我们都可以一直消掉3列
所以我们可以打表在一个范围里,当n和m很大时,都可以通过消掉3列,消掉3行来使得其落在打表范围里
当n等于5并且m等于5时,可以这么消
当n大于等于6,并且m大于等于6时,更加可以消3行3列
但是当n为4,m为5时,就只能消掉3列,行就不行了,所以当n和m都大于等于5时,才消3行3列,所以我们打表打到4*4
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<deque>
#include<cstdio>
#define endl '\n'
//#define int long long
using namespace std;
int ans[4][4]=
{
{1,1,2,2},
{1,1,2,1},
{2,2,2,2},
{2,1,2,1}
};
void solve()
{
int n,m;
cin>>n>>m;
if(n>m) swap(n,m);
if(n==1){
cout<<(m+1)/2;
return;
}
while(n>=5) n-=3;
while(m>=5) m-=3;
cout<<ans[n-1][m-1]<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}
1012 a-b Problem
对于每一个ai,bi,求它们的和,然后从大到小排序,依次取
原因在于自己取了其中一个,对方没有取另一个,那么自己比对方就多了两者之和
AC代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define endl '\n'
//#define int long long
using namespace std;
const int N=1e5+10;
//typedef pair<int,int>PII;
typedef long long ll;
ll n;
struct node{
ll a;
ll b;
ll sum;
bool operator<(const node &W)const{
return sum>W.sum;
}
}ans[N];
void solve()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>ans[i].a>>ans[i].b;
ans[i].sum=ans[i].a+ans[i].b;
}
sort(ans+1,ans+1+n);
ll sum1=0,sum2=0;
for(int i=1;i<=n;i++){
if(i%2==1) sum1+=ans[i].a;
else sum2+=ans[i].b;
}
cout<<sum1-sum2<<endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
while(t--)
solve();
return 0;
}