Dashboard - Codeforces Round #806 (Div. 4) - Codeforces
题意:给出多个字符串,问能被其它字符串拼凑则这一个串记作1否则记作0
正解:因为字符串长度最多为8,substr枚举一下就好
void solved()
{
int n;cin>>n;
map<string,int>mp;
for(int i=1;i<=n;i++)
{
cin>>str[i];
mp[str[i]]++;
}
for(int i=1;i<=n;i++)
{
bool ok=0;
string s=str[i];
for(int i=1;i<=s.size()-1;i++)
{
string a=s.substr(0,i),b=s.substr(i,s.size()-1);
if(mp[a]&&mp[b])ok=1;
}
if(ok)cout<<1;
else cout<<0;
}
puts("");
}
中心对称,思路简单,主要看代码实现
以下给出顺序遍历时 中心对称的坐标
a=mp[i][j],b=mp[j][n-i+1],尤其前两项90度旋转就已经可以好好利用了
c=mp[n-i+1][n-j+1],d=mp[n-j+1][i];
char mp[110][110];
bool vis[110][110];
void solved()
{
memset(vis,0,sizeof vis);
int n;cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>mp[i][j];
int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
char a=mp[i][j],b=mp[j][n-i+1],c=mp[n-i+1][n-j+1],d=mp[n-j+1][i];
if(vis[i][j])continue;
vis[i][j]=1,vis[j][n-i+1]=1,vis[n-i+1][n-j+1]=1,vis[n-j+1][i]=1;
int aa=0,bb=0;
if(a=='0')aa++;else bb++;
if(b=='0')aa++;else bb++;
if(c=='0')aa++;else bb++;
if(d=='0')aa++;else bb++;
ans+=min(aa,bb);
}
cout<<ans<<'\n';
}
题意:统计i<a[i]<j<a[j]的对数
正解:先处理i<a[i]
接下来只要找a[j]>i
暴力还是会超,这里考虑树状数组or直接前缀和,二分来做
只讲树状数组
只要查询每个a[i]和树状数组中计数的i的关系就行add(i,1)
模拟知query到的会是1到a[i],我们要求小于a[i],因此query a[i]-1
int lowbit(int x)
{
return x&-x;
}
void add(int x,int k)
{
while(x<=n)
{
tr[x]+=k;
x+=lowbit(x);
}
}
int sum(int x)
{
int ans=0;
while(x>0)
{
ans+=tr[x];
x-=lowbit(x);
}
return ans;
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
cin>>n;
ll ans=0;
mem(tr,0);
for(int i=1;i<=n;i++)
{
cin>>a[i];
if(a[i]<i)
{
add(i,1);
ans+=sum(a[i]-1);
}
}
cout<<ans<<endl;
}
题意:好钥匙花费费用,坏钥匙不花费费用,但是所有箱子价值减半,可以无限欠费,求打开箱子得到费用求最大费用
一眼Dp
可以贪心做:先选好钥匙,再选坏钥匙
证明:第一次欠费,(a[i]+a[i+1])/2>a[i]+a[i+1]/2不可能成立
ll ans,s[maxn],ANS,k,m[40]={1};
int main(){
for(int i=1;i<=33;i++) m[i]=m[i-1]*2ll;
cin>>t;
while(t--){
cin>>n>>k;
ll res=-1;
for(int i=1;i<=n;i++) cin>>a[i], s[i]=s[i-1]+a[i];
for(int x=0;x<=n;x++){
ans=s[x]-k*1ll*x;
for(int i=x+1;i<=min(x+32,n);i++) ans+=a[i]/m[i-x];
res=max(res,ans);
}
cout<<res<<endl;
}
Dashboard - Codeforces Round #807 (Div. 2) - Codeforces
dv2
一维排序,站成两排,以+n对应就Ok不用转二维
void solved()
{
int n,x;cin>>n>>x;
int g[10][110];
int q[110];
for(int i=1;i<=2*n;i++)cin>>q[i];
sort(q+1,q+2*n+1);
int cnt=0;
for(int i=1;i<=2;i++)
{
for(int j=1;j<=n;j++)
g[i][j]=q[++cnt];
}
bool ok=1;
for(int i=1;i<=2;i++)
{
for(int j=1;j<=n;j++)
if(g[1][j]+x>g[2][j]){puts("NO");return;}
}
puts("YES");
}
思维有0就补上,否则都需要清空掉即算作计数
void solved()
{
ll n;cin>>n;
ll ans=0;
for(int i=1;i<=n;i++)cin>>q[i];
for(int i=1;i<n-1;i++)
if(q[i]&&!q[i+1])q[i]-=1,q[i+1]=1,ans++;
for(int i=1;i<n;i++)
ans+=q[i];
cout<<ans<<'\n';
}
题意:每次复制字符串接在前一个字符串后面,查询第k个字符
本题是活用了数组
存直接用c次去存
找就从最后一层往回找
ll n,c,q;
void solved()
{
cin>>n>>c>>q;
string ss;cin>>ss;ss=" "+ss;
int len=ss.size()-1;
ll s[40],l[40],r[40];
s[0]=len;
for(int i=1;i<=c;i++)
{
ll x,y;cin>>x>>y;
复制的左右界
l[i]=x,r[i]=y;
串的当前长度
s[i]=s[i-1]+y-x+1;
}
while(q--)
{
ll k;cin>>k;
二分k找是s中的哪一次复制
while(k>s[0])
{
二分左端点s,右s+c+1,-s返回下标(不然会是地址)
ll x=lower_bound(s,s+c+1,k)-s;
更新k直到初始字符串
看K在从l开始的哪里,-1是l[x]占了一项
k=l[x]+k-s[x-1]-1;
}
cout<<ss[k]<<'\n';
}
}
题意:s串能否变成t串,操作只能选i+1,i-1,必须不同,改变i
连续的1,0块个数相同,首尾串相同,才能合题意
移动次数找规律,模拟,是存的下标差
ll n;
string s,t;
void solve(){
cin>>n;
cin>>s>>t;
vector<int> a,b;
for(int i=0;s[i];i++){
if(s[i]!=s[i+1]) a.pb(i);
if(t[i]!=t[i+1]) b.pb(i);
}
if(a.size()!=b.size()||s[0]!=t[0]||s[n-1]!=t[n-1]){
cout<<-1<<endl;
return;
}
ll ans=0;
for(int i=0;i<a.size();i++){
ans+=abs(a[i]-b[i]);
}
cout<<ans<<endl;
}