iwtgm-10
A.
手玩,左右循环后对应位置字符相同,可得到:
如果只有两个字符一定可以
如果是奇数,那么必须全部相同
如果是偶数,那么奇数位置的要全部相同,偶数位置的要全部相同
卡的点是相对位置不变,可以删除任意位置,如何判奇数全部相同,偶数全部相同
后来看@zys111代码,因为只有两种字符(可相同),可以用一个变量记录下一个需要的字符判
归纳,两个字符一定可以因为奇数只有一个,偶数只有一个,那么一定满足奇数位置和偶数位置分别相同
如果字符全部相同,那么也满足奇数位置和偶数位置分别相同,并且任意个数都可
void solve(){
string s;cin>>s;
int ans=inf,cnt,res;
for(int i=0;i<=9;i++){
for(int j=0;j<=9;j++){
res=i;cnt=0;
for(int k=0;k<s.size();k++){
if(s[k]-'0'==res){
if(res==i)res=j;
else res=i;
}else cnt++;
}
if(res==i)ans=min(ans,cnt);//两种不同字符的情况,两种字符数必须相同,此时变量为第一种字符的状态
}
}
cout<<ans<<endl;
}
B.
求前n个数范围内有几个与i互质的和
欧拉函数可算对于i来说,在小于等于i的范围内有几个与i互质
欧拉筛法+欧拉函数可快速算出前n个数的欧拉函数的和
如果m<(n-1)或者m>这个和都不合法(必须要联通且这个和已经是最大的边数)直接退出
如果合法,m只有1e5,在n范围内暴力找与i互质的数输出即可
bool is_prime[N];//是否是质数,0为是,1为不是
int prime[N];//质数数组
int top=1;//质数的下标
int ola[N];//i的欧拉函数值
ll sum[N];//求1-n的欧拉函数的和
int gcd(int a, int b) {
return b > 0 ? gcd(b, a % b) : a;
}
void get_prime(){
ola[1]=1;
for(int i=2;i<N;i++){
if(!is_prime[i]){//是质数
prime[top]=i;//存质数
top++;//下标后移
ola[i]=i-1;//质数的欧拉函数是质数-1
}
for(int j=1;j<top;j++){//最小到达遍历质数数组
if(i*prime[j]>N)break;
is_prime[i*prime[j]]=1;//标记质数的倍数即合数
if(i%prime[j]==0){
ola[i*prime[j]]=ola[i]*prime[j];//如果i%p==0,那么φ(i*p)=φ(i)*p
break;//若i是之前质数的倍数,说明这个倍数会在后面的循环内被筛去,无需继续循环
}
ola[i* prime[j]]=ola[i]*(prime[j]-1);//如果i%p!=0,那么 φ(i*p)=φ(i)*(p-1) 其中p为质数
}
}
}
void solve(){
get_prime();
for(int i=1;i<N;i++){
sum[i]+=sum[i-1]+1ll*ola[i];
}
int n,m;cin>>n>>m;
if(n==1){
cout<<"Impossible";return ;
}
if(m<(n-1)||m>sum[n]-1){
cout<<"Impossible";return ;
}
//cout<<sum[n];
cout<<"Possible"<<endl;
int cnt=0;
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
if(gcd(i,j)==1){
cout<<i<<' '<<j<<endl;
cnt++;
if(cnt==m)return ;
}
}
}
}
C.
若第一不要求一定要从0开始,
那么就是贪心,预处理出每个转移器的花费(a[i]+min(i,n-i+1)),然后排序从小到大取就好
因为每次用完转移器要么被转移到0要么转移到n+1,且我们用一个转移器的步数是固定的,转移到离下一个花费最少的转移器更近的点(0或n+1)即可
但现在要求第一步一定要从0开始,考虑如何消除这个影响
先按之前贪心的做法得到一个排序好的数组,对这个数组求一个前缀和,此时下标的值就是能取几个转移器,pre[i]就是总花费
可以枚举第一步选的是哪一个转移器,设下标为id,用花费-差价(没有实际减,只是用这个值去二分)(贪心最优和从0到这个转移器),
此时二分看前缀和数组下标能取到几,设为p,如果p>id,说明此时花费已经包含了我枚举的第一个转移器(这里是贪心取),但差价已经计算过了,下标-1就是答案(因为upper_bound()取的是大于花费的)
如果p<=id,说明没有算第一步的转移器,那么把花费-枚举的那个转移器的花费后再去二分
得到的下标p不用-1因为多的那个1与枚举的那个1抵消
ll n,c,pre[N],ans,cnt;
pair<ll,ll>pa[N];
void solve(){
ans=0;cin>>n>>c;
for(ll i=1,x;i<=n;i++){
cin>>x;
pa[i]={x+min(i,n-i+1),x+i};
}
sort(pa+1,pa+1+n);
for(int i=1;i<=n;i++)pre[i]=pre[i-1]+pa[i].first;
for(int i=1;i<=n;i++){
if(c<pa[i].second)continue;
cnt= upper_bound(pre+1,pre+1+n,c-pa[i].second+pa[i].first)-pre-1;//upper_bound()给出的下标是大于花费的,所以-1
if(cnt<i)cnt= upper_bound(pre+1,pre+1+n,c-pa[i].second)-pre;//大于花费的那个1与枚举的那个1抵消,不用-1
ans=max(ans,cnt);
}
cout<<ans<<endl;
}