签到
题意:给定1,2的数量,判断是否能用加减符号使得这些1,2计算出0
cpp
void solve()
{
cin>>n>>m;
if(n%2)cout<<"NO\n";
else
{
if(m%2==0||n)cout<<"YES\n";
else cout<<"NO\n";
}
return ;
}
签到
题意:给定01序列,问从上到下,从左到右排列是否可以得到一个周围为1,内部为0的正方形
cpp
void solve()
{
string s;
cin>>n;
cin>>s;
int t=sqrt(n);
if(t*t!=n)
{
cout<<"No\n";
return;
}
else
{
int idx=0;
for(int i=0;i<t;i++)
{
for(int j=0;j<t;j++)
{
int now=i*t+j;
if(i==0||j==0||i==t-1||j==t-1)
{
if(s[now]=='0')
{
cout<<"No\n";
return;
}
}
else if(s[now]=='1')
{
cout<<"No\n";
return;
}
}
}
}
cout<<"Yes\n";
return ;
}
题意:给定左右边界了l,r,问在范围内凑出最长的满足a[i]-a[i-1]<a[i+1]-a[i](i>=2)的最长数组的长度
思路:最优一定是前后两项差从左到右分别为1,2,3,4...,所以二分数组最后一个元素,满足小于r-l的第一个元素位置,再+1就是答案
cpp
int n,m;
int cha;
bool check(int x)
{
return (x+1)*x/2>cha;
}
void solve()
{
cin>>n>>m;
cha=m-n;
int l=0,r=1e8;
while(l+1<r)
{
int mid=l+r>>1;
check(mid)?r=mid:l=mid;
}
cout<<l+1<<'\n';
return ;
}
题意:输入一个数组大小n,然后输入n个数q[i](1<=i<=n)代表i可以到达q[i](保证q数组一定是一个排列),然后输入一个01串,当第i个位置为'1'代表为白块,为'0'代表为黑块,f[i]为能够到达i这个点的所有黑块的数量,输出所有f[i](1<=i<=n)
例如:
输入
2
2 1
00
输出
2 2
(因为1位置的点都能由1,2到达)
思路:并查集,把所有有联系的点都缩到一个根上(由于是一个排列,所以所有可以直接可以到达或者间接到达的点都可以形成一个环,也就是相互到达),最后问f[i]只需要把一个环中的所有店都累加到find(i),也就是根节点上
代码:
cpp
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define sd(x) scanf("%Lf",&x)
#define sdd(x,y) scanf("%Lf %Lf",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define _pre(i,a,b) for(int i=(a);i>=(b);--i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e6+10,INF=4e18;
int n,m;
int f[N],q[N],cnt[N];
bool st[N];
int find(int x)
{
if(x!=f[x])return f[x]=find(f[x]);
return f[x];
}
void root(int a,int b)
{
int x=find(a),y=find(b);
if(x!=y)f[x]=y;
}
void solve()
{
cin>>n;
_rep(i,1,n)cin>>q[i],f[i]=i,st[i]=false,cnt[i]=0;
string s;
cin>>s;
s=" "+s;
_rep(i,1,n)
{
int now=i;
while(!st[now])
{
st[now]=true;
root(now,q[now]);
now=q[now];
}
}
_rep(i,1,n)
if(s[i]=='0')
cnt[find(i)]++;
_rep(i,1,n)
cout<<cnt[find(i)]<<" ";
cout<<'\n';
return ;
}
signed main()
{
IOS;
int T=1;
cin>>T;
while(T--)
solve();
return 0;
}
题意:给定一个字符串,现在有两个操作
1:选一个字母删除(但是这个最多只能操作一次)
2:将一个位置的字母改成另一个字母
问你把这个字符串变成一个:奇数位置字母都相同,偶数位置字母都相同 的字符串的最小操作次数
思路
只要发现一个特点就可以想到这个思路,那就是当你选择把当前这个点i的字母删除之后,后面所有的字母所在的奇偶位置就发生了互换
1.首先考虑不删除字母的情况
维护一个hou[26][2]的数组,其中第一维代表哪个字母(0~25),第二维 0/1 代表 奇数位/偶数位
那么我首先遍历奇数位置的所有字母,求和sum就是奇数位置字母的数量,求最大值ma就是奇数位置 字母的众数那么sum-ma就是奇数位置最少需要改变的字母的数量
偶数位置同理,那么就能求导不删除字母情况下最小操作次数
2,考虑删除字母的情况
假如我现在删除的是i号点,那么1~i-1号点的奇偶性质未发生改变,那么我就从小到大遍历即可,i+1~n号点的奇偶性质全部发生了改变,那么显然如果我能预处理出i+1~n的所有状态,也就是前面说到的hou[26][2],那么奇数位本来是hou[0~25][0]现在只需要考虑hou[0~25][1],偶数位置同理,那么就可以发现这个hou[0~25][2]显然可以提前预处理出来,然后遍历到第i个点的时候把1~i的状态删去就行,这些都可以线性处理,时间复杂度O(26*n)
代码:
cpp
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define sd(x) scanf("%Lf",&x)
#define sdd(x,y) scanf("%Lf %Lf",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define _pre(i,a,b) for(int i=(a);i>=(b);--i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e6+10,INF=4e18;
int n,m;
int now[26][2],hou[26][2];//now储存1~i-1的状态,hou储存i+1~n的状态
void solve()
{
cin>>n;
string s;
cin>>s;
memset(now,0,sizeof(now));
memset(hou,0,sizeof(hou));
s=" "+s;
_rep(i,1,n)
hou[s[i]-'a'][i%2]++;
int res=0,sum,ma;
_rep(j,0,1)
{
sum=0;
ma=0;
_rep(i,0,25)
{
sum+=hou[i][j];
ma=max(hou[i][j],ma);
}
res+=sum-ma;
}
if(n%2)
{
res=INF;
_rep(i,1,n)
{
int nowres=0;
hou[s[i]-'a'][i%2]--;
_rep(j,0,1)
{
sum=0;
ma=0;
_rep(k,0,25)
{
sum+=hou[k][j];
sum+=now[k][j^1];
ma=max(ma,hou[k][j]+now[k][j^1]);
}
nowres+=sum-ma;
}
now[s[i]-'a'][i%2]++;
res=min(res,nowres+1);
}
}
cout<<res<<"\n";
return ;
}
signed main()
{
IOS;
int T=1;
cin>>T;
while(T--)
solve();
return 0;
}
题意:给定一个数组,为元素之间两两相乘(a[1]*a[2]和a[2]*a[1]重复不算)的平均数是什么
思路:
假设四个元素
那么答案就是
等价于
用一个后缀和维护形如的东西这道题就轻松解决了,只需要注意一下取模和乘法逆元的问题就行了
cpp
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <cmath>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <unordered_map>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define pp pop_back()
#define int long long
#define laile cout<<"laile"<<endl
#define lowbit(x) ((x)&(-x))
#define double long double
#define sf(x) scanf("%lld",&x)
#define sff(x,y) scanf("%lld %lld",&x,&y)
#define sd(x) scanf("%Lf",&x)
#define sdd(x,y) scanf("%Lf %Lf",&x,&y)
#define _for(i,n) for(int i=0;i<(n);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
#define _pre(i,a,b) for(int i=(a);i>=(b);--i)
#define all(x) (x).begin(), (x).end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const int N=1e6+10,INF=4e18,P=1e9+7;
int n,m;
int hou[N],q[N];
int qmi(int a,int b)
{
int res=1;
while(b)
{
if(b&1)res=res*a%P;
a=a*a%P;
b>>=1;
}
return res;
}
void solve()
{
cin>>n;
_rep(i,1,n)cin>>q[i];
hou[n+1]=0;
_pre(i,n,1)
hou[i]=hou[i+1]+q[i];
int res=0;
_rep(i,1,n)
{
res+=(q[i]*(hou[i+1]%P)%P);
res%=P;
}
// cout<<"res="<<res<<" "<<n<<endl;
cout<<(res*qmi((n*(n-1)/2)%P,P-2)%P)<<'\n';
return ;
}
signed main()
{
IOS;
int T=1;
cin>>T;
while(T--)
solve();
return 0;
}