A. Windblume Ode
题意:就是从n个数里面挑p(要求最大)个数的和为合数,输出所挑选的数的下标,顺序随便
思路:p的可能值只有n or n-1,如果所有加起来的和为合数,输出n,否则,在奇数中挑一个数减去,使得和为合数,
证明:假设偶数有a个,奇数有b个,a个偶数相加肯定为合数,
(1)如果b是偶数,则奇数可以两两配对,所以最后的和为偶数,肯定为合数
(2)如果b为奇数,那么最后的和可能为合数,可能不是,如果不是,和肯定为奇数,所以需要减去一个奇数,使得和为合数
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<double,double> pdd;
const int inf=0x3f3f3f3f;
const int maxn=1e5+10;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int a[200];
int sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
int flag=0;
for(int i=2;i*i<=sum;i++)
{
if(sum%i==0)
{
flag=1;
break;
}
}
if(flag)
{
cout<<n<<endl;
for(int i=1;i<=n;i++)
{
cout<<i<<" ";
}
cout<<endl;
}
else
{
int k=0;
cout<<n-1<<endl;
for(int i=1;i<=n;i++)
{
if(a[i]%2&&k==0)
{
int f=0;
for(int j=2;j*j<=sum-a[i];j++)
{
if((sum-a[i])%j==0)
{
f=1;
break;
}
}
if(f)
{
k=1;
continue;
}
else
{
cout<<i<<" ";
}
}
else
{
cout<<i<<" ";
}
}
cout<<endl;
}
}
}
B. Omkar and Heavenly Tree
题意:有一个n节点的图,有m个限制,输入限制a b c,代表a c中间的简单路径中不能有b节点,(n>m)构造这个图
思路:因为n>m所以肯定有一个节点没有任何限制,我们可以把它放中间,其他点围成一圈,就可以了,这样点和点之间都是这个没有任何限制的点,
代码
#include<bits/stdc++.h>
using namespace std;
int vis[100005];
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
cin>>n>>m;
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++)
{
int a,b,c;
cin>>a>>b>>c;
vis[b]=1;
}
int id=0;
for(int i=1;i<=n;i++)
{
if(vis[i]==0)
{
id=i;
}
}
for(int i=1;i<=n;i++)
{
if(id==i)continue;
cout<<id<<" "<<i<<endl;
}
}
}
C. Omkar and Determination
题意:有一个n×m图,有些格子被填充,有些空着,空单元格可通过,向上或向左移动走出边界,所以我们可以通过原图确定一个新图,上面标记着那些单元个可以走出边界那些不行,这个新图也可以反推出原图,如果这个新图反推出的图是唯一的,则称这个原图是可确定的,现在问你由Xn,Xn+1,··· Xn+m列组成的图是不是可确定的
思路:如果一个空单元格走不出边界,那么这个单元格对应的新图上走不出去,那么这个单元格也可以是填充的,所以这个点反推回来会有两种情况,所以我们要统计原图上空单元格走不出去的点,利用前缀和,如果q[l]=q[r]代表l+1~r间没有不符合的点,输出YES,否则输出NO,并且,如果查询范围l=r直接输出YES
代码
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<cstring>
using namespace std;
int vis[1000005];
int q[1000005];
char s[1000005];
char c[1000005];
int main()
{
int n, m;
cin >> n >> m;
int cnt = 0;
for (int i = 0; i < n; i++)
{
cin >> c;
for (int j = 0; j < m; j++)
{
if (i > 0 && j > 0)
{
if (s[j] == 'X' && c[j - 1] == 'X')
{
vis[j]++;
}
}
}
strcpy(s, c);
}
for (int i = 1; i < m; i++)
{
q[i] = q[i - 1] + vis[i];
}
int t;
cin >> t;
while (t--)
{
int l, r;
cin >> l >> r;
if (l == r)cout << "YES" << endl;
else
{
r--,l--;
if (q[r] == q[l])
cout << "YES" << endl;
else
{
cout << "NO" << endl;
}
}
}
}
D. Omkar and the Meaning of Life
题意:你可以查询不超过2*n次,每次查询输出a1~an,设sj=aj+pj;如果s中有重复的,会返回第一个重复值的下标,求p数组(p数组是n的一个排列,里面每个数在1到n之间,不重复)
思路:
每次查询可以得到其它数与pn的差距
左边得到比pn小的数的差距,右边得到比pn大的数的差距
代码
#include<bits/stdc++.h>
using namespace std;
int d[110];
int n;
int main()
{
cin>>n;
for(int i=2;i<=n;i++)
{
cout<<"? ";
for(int j=1;j<n;j++)
{
cout<<i<<" ";
}
cout<<1<<endl;
fflush(stdout);
int x;
cin>>x;
d[x]=1-i;//与pn的差距
}
for(int i=2;i<=n;i++)
{
cout<<"? ";
for(int j=1;j<n;j++)
{
cout<<1<<" ";
}
cout<<i<<endl;
fflush(stdout);
int x;
cin>>x;
d[x]=i-1;
}
int mi=1;
for(int i=1;i<=n;i++)
{
if(d[mi]>d[i])
{
mi=i;
}
}
int ans=-d[mi]+1;
cout<<"! ";
for(int i=1;i<=n;i++)
{
cout<<d[i]+ans<<" ";
}
fflush(stdout);
}