大意:保证任意2个ai和不等于任意一个ai;
思路:全都是1即可
int T,n;
int main()
{
cin>>T;
while(T--)
{
cin>>n;
rep(i,0,n)
cout<<"1 ";
cout<<"\n";
}
return 0;
}
B. Omkar and Last Class of Math
大意:找到一组a,b,使a+b==n,并且使得lcm(a,b)尽量小
思路:lcm(a,b)尽量小,那b肯定是a的m倍,这样lcm就是b了,而a+b=n,所以(m+1)/mb=n,b=nm/(m+1),找到第一个满足n%(m+1)==0的m值即可,暴力找的话因为n是1e9,会T,所以用素数筛思想加速一下
ll T,n;
int main()
{
cin>>T;
while(T--)
{
cin>>n;
rep(i,1,sqrt(n)+1)
{
if(n%(i+1)==0)
{
cout<<n-i*n/(i+1)<<" "<<i*n/(i+1)<<"\n";
break;
}
if(i==(int)sqrt(n))
{
cout<<1<<" "<<n-1<<"\n";
}
}
//b=ma
//a+b=n
//(m+1)a=n; (m+1)/m*b=n
//(m+1)b=m*n
//b=m/(m+1)*n
}
return 0;
}
C. Omkar and Baseball
思路:看到这个题,第一反应就是是不是分区域,以不需要动的点为间隔,全都是乱的点为一个区域,找到全都是乱的点的区域个数,输出,然后打出了这个
int T,n;
int a[maxn];
PII b[maxn];
int cmp(PII a,PII b)
{
if(a.first==b.first)
return a.second<b.second;
return a.first<b.first;
}
int main()
{
cin>>T;
while(T--)
{
cin>>n;
rep(i,0,n)
{
cin>>a[i];
b[i].first=a[i];
b[i].second=i;
}
sort(b,b+n);
int sum=0;
int cnt=0;
rep(i,0,n)
{
if(a[i]==b[i].first && i==b[i].second)
{
if(cnt)
sum++;
cnt=0;
}
else
cnt++;
}
if(cnt)
sum++;
cout<<sum<<"\n";
}
return 0;
}
然后,然后就华丽丽的wa3了,然后思考了下,为啥不对呢?
哦,假如sum>=3的话,其实完全可以第一次直接动1~n,把他不管之前是啥,排成一个既不是初始状态,也不是递增的就行,当n>=3的必然可以,而n<3的时候sum也不能达到3,所以sum的最大值其实就是2,所以在输出的时候,sum改成min(2,sum)即可
int T,n;
int a[maxn];
PII b[maxn];
int cmp(PII a,PII b)
{
if(a.first==b.first)
return a.second<b.second;
return a.first<b.first;
}
int main()
{
cin>>T;
while(T--)
{
cin>>n;
rep(i,0,n)
{
cin>>a[i];
b[i].first=a[i];
b[i].second=i;
}
sort(b,b+n);
int sum=0;
int cnt=0;
rep(i,0,n)
{
if(a[i]==b[i].first && i==b[i].second)
{
if(cnt)
sum++;
cnt=0;
}
else
cnt++;
}
if(cnt)
sum++;
if(sum<=2)
cout<<sum<<"\n";
else
cout<<2<<"\n";
}
return 0;
}
D. Omkar and Circle
大意:给你一个n长度的数组,首尾相接,你可以进行(n-1)/2次操作,每次操作[a[i],a[i+1],a[i+2]]替换成[a[i]+a[i+2]],使最后a[i]最大,问你最大值
分析:每次假如以i为中心动,那就相当于删去a[i],将a[i-1]和a[i+1]合并,而因为这2者合并了,只能一块删去或者保留,所以这(n-1)/2次操作一定不存在相邻的,假如某次操作是取i,又有次操作是动i+1,那么a[i]和a[i+1]就会被动2次,这明显是不合理的,所以每次操作都是至少间隔1, 并且每次操作的本质都是从总和里删去a[i]的值,所以问题转换成了
进行(n-1)/2次操作,每次删去a[i]的值,每次操作至少间隔1,问这些删去的a[i]的和最小值
而因为一共是(n-1)/2次操作,而每次又至少间隔1,设k=(n-1)/2,有k-1次操作是间隔1,1次操作跟之前的是间隔2,枚举哪一位间隔2就行,用前缀和还可以进一步加速
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=200005;
const int inf=0x3f3f3f3f;
const int INF=0x7f7f7f7f;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// head
ll n,m;
long long a[maxn];
long long sum1[maxn];
ll sum2[maxn];
int main()
{
cin>>n;
rep(i,1,n+1)
{
cin>>a[i];
if(i&1)
{//1 3 5
if(i>=3)
sum1[i]=sum1[i-2]+a[i];
else
sum1[i]=a[i];
}
else
{//2 4 6
sum2[i]=sum2[i-2]+a[i];
}
}
if(n==1)
{
cout<<sum1[1]<<"\n";
return 0;
}
m=(n-1)/2;
ll ans=sum2[n-1];
ans=min(ans,sum1[n]-sum1[1]);
ans=min(ans,sum1[n-2]);
for(int i=2;i<=m;i++)
{
ans=min(ans,sum1[2*i-3]+sum2[n-1]-sum2[2*i-2]);
ans=min(ans,sum2[2*i-2]+sum1[n]-sum1[2*i-1]);
}
cout<<sum2[n-1]+sum1[n]-ans<<"\n";
return 0;
}
//选了i,i+1和i-1都不能选了
//(n-1)/2
其实就是个区间dp,n和m最大值才100, n 4 n ^ 4 n4水过
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
typedef long long ll;
typedef double db;
typedef pair<int,int> PII;
typedef vector<int> VI;
const ll mod=1000000007;
const int maxn=200;
const int inf=0x3f3f3f3f;
const int INF=0x7f7f7f7f;
ll gcd(ll a,ll b){ return b?gcd(b,a%b):a;}
#define ms(a) memset(a,0,sizeof(a))
#define mss(a) memset(a,-1,sizeof(a))
#define msi(a) memset(a,inf,sizeof(a))
#define iossync ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
// head
int n,m;
int l,r;
int n1;
int dp1[maxn][maxn],dp2[maxn][maxn];
int dp[maxn][maxn];
int main()
{
cin>>n>>m;
rep(i,1,n+1)
{
cin>>n1;
rep(j,1,n1+1)
{
cin>>l>>r;
rep(z,l,r+1)
{//标记每个点的属于哪个区域,这里似乎可以用离散化,直接用标号来确定,emmmm
dp1[i][z]=l;
dp2[i][z]=r;
}
}
}//列 区间dp dp[i][j] dp[i][j] dp[i][k]+dp[k+1][j]+a*a
per(i,1,m+1)
{
rep(j,1,m+1)
{
rep(z,1,j+1)
{
int sum=0;
rep(k,1,n+1)//行
{
// if(check())
if( dp2[k][z]<=j && dp1[k][z]>=i)
{
sum++;
}
// dp[]
}
dp[i][j]=max(dp[i][j],dp[i][z-1]+dp[z+1][j]+sum*sum);
}
}
}
cout<<dp[1][m]<<"\n";
return 0;
}
F. Omkar and Modes
交互题他来啦(cout.flush();)
某人说过,交互题90%都是二分,剩下的10%我也不会
所以这题直接考虑二分
先分析题意,总序列不降,所以每次返回的众数,以及个数,就是代表在[l,r]这段区间里,有f个相连的x,
也就是说即使这f个x在最左边,那也是[l,l+f-1],在最右边也是[r-f+1,r],也就是说[l+f-1,r-f+1]这个区间必然全是x,当然你得满足l+f-1 < = r-f+1,然后就把这个区域的填补上,再继续做剩下的区域就好,具体可以看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+50;
#define rep(i,a,n) for(int i=a;i<n;i++)
int a[maxn];
int l1,r1;
//int n,x,f;
int n;
void solve(int l,int r)
{
int x,f;
if(l>r)
return ;
cout<<"? "<<l<<" "<<r<<"\n";
cout.flush();
cin>>x>>f;
l1=r-f+1,r1=l+f-1;
if(l1<=r1)
{
rep(i,l1,r1+1)
a[i]=x;
solve(l,r-f);
solve(l+f,r);
}
else
{
solve(l,(l+r)>>1);
solve(((l+r)>>1)+1,r);
}
}
int main()
{
cin>>n;
// cout<<"? "<<1<<" "<<n<<"\n";
// cout.flush();
// cin>>x>>f;
solve(1,n);
cout<<"! ";
rep(i,1,n+1)
cout<<a[i]<<" ";
return 0;
}
//r-f+1 l+f-1 保底 x
//5 2
//2 2