J - Welcome Party
模拟比赛的时候,做到这个题脑子就不转了,一直是另外两个队友在做这个题,比完赛后看题解知道思路后竟然一发就过了,,也没用到并查集,只是简单的bfs(bfs yyds);可以发现这m条关系会把人分成若干个组,有几个组答案就是几,这个直接用bfs做就行,要从1到n开始做,因为我们还要把每个组的最小值入队列,正序遍历正好满足这个条件了;弄完之后,每个组的最小值在队列了,然后每次输出队列的最小值(这个队列指的是优先队列),然后将和他一组的人入队列,再输出下一个最小值,知道队列为空;
(2条消息) J - Welcome Party(2019浙江省省赛)(bfs+优先队列)_Dream Flying Eagle的博客-CSDN博客
#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,m,vis[1000006];
vector<ll>v[1000006];
priority_queue<ll,vector<ll>,greater<ll> >q;
void bfs(ll u){
queue<ll>q1;
q1.push(u);
while(!q1.empty()){
ll now=q1.front();q1.pop();
if(vis[now]) continue;
vis[now]=1;
for(int i=0;i<v[now].size();i++){
ll j=v[now][i];
if(!vis[j]) q1.push(j);
}
}
}
int main(){
// freopen("in.txt","r",stdin);
scanf("%lld",&t);
while(t--){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) vis[i]=0,v[i].clear();
for(int i=1;i<=m;i++){
ll x,y;
scanf("%lld%lld",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
ll ans=0;
for(int i=1;i<=n;i++)
if(!vis[i]) bfs(i),ans++,q.push(i);
printf("%lld\n",ans);
for(int i=1;i<=n;i++) vis[i]=0;
while(!q.empty()){
ll u=q.top();q.pop();
if(vis[u]) continue;
vis[u]=1;
if(u==1) printf("%lld",u);
else printf(" %lld",u);
for(int i=0;i<v[u].size();i++){
ll j=v[u][i];
if(!vis[j]) q.push(j);
}
}
printf("\n");
}
return 0;
}
K - Strings in the Pocket 马拉车算法
通过这个题新学了个马拉车算法,可以求出最大回文串的长度;当s==t的话,用马拉车算法求出以s[i]为中心的回文串最大长度全部除以2加起来就是答案;若不想等的话,那就找到第一个和最后一个不相等的位置,看看反转后可不可以,不可以就是0,可以就继续向外扩展;
(2条消息) 2019年浙江省赛K题 Strings in the Pocket (Manachar)_ccdxc的博客-CSDN博客
马拉车算法,这个人讲的挺好(2条消息) Manacher算法(马拉车算法)_nowting_csdn的博客-CSDN博客_马拉车算法
#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll n,ans,len;
string s,t;
void manachar(){
string str="$#";
for(int i=0;i<len;i++){
str+=s[i];str+="#";
}
ll m=str.size();
vector<ll>p(m,0);
ll id=0,mx=0;
for(int i=1;i<m;i++){
p[i]=mx>i?min(p[id*2-i],mx-i):1LL;
while(str[i+p[i]]==str[i-p[i]]) p[i]++;
if(i+p[i]>mx){
mx=p[i]+i;
id=i;
}
ans+=p[i]/2;//p[i]-1是原来字符串的长度,只考虑一边的话就是(p[i]-1+1)/2也就是p[i]/2了
}
}
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld",&n);
while(n--){
cin>>s>>t;
len=s.size();
ans=0;
if(s==t) manachar();
else{
ll l=0,r=len-1;
while(s[l]==t[l]&&l<len) l++;
while(s[r]==t[r]&&r>=0) r--;
string s1=s.substr(l,r-l+1);
string t1=t.substr(l,r-l+1);
reverse(s1.begin(),s1.end());
if(s1==t1){
ans=1;
for(int i=1;i<min(l+1,len-r);i++){
if(s[l-i]==s[r+i]) ans++;
else break;
}
}
}
printf("%lld\n",ans);
}
return 0;
}
B - Element Swapping 数学推导
这题需要大胆的推公式,模拟比赛的时候看懂题意后就没敢往下做了,主要都在做J题,没有心思再做这个题;求出x,y和sum1(现在的x),sum2(现在的y)的关系,然后可以得出两个数的和与x,y,sum1,sum2有关系,之后再根据第一个式子可以得出能求出b的下标的式子;
(2条消息) 2019 浙江省赛 B-Element Swapping_yintama%QCT的博客-CSDN博客
#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,x,y,a,b[100005];
map<ll,ll>mp;
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld",&t);
while(t--){
scanf("%lld%lld%lld",&n,&x,&y);
ll sum1=0,sum2=0,ans=0;
for(int i=1;i<=n;i++){
scanf("%lld",&b[i]);
mp[b[i]]++;
sum1+=i*b[i];sum2+=i*b[i]*b[i];
}
if(x==sum1&&y==sum2){
for(int i=1;i<=n;i++){
ll num=mp[b[i]];
if(num)
ans+=num*(num-1)/2;
mp[b[i]]=0;
}
}
else if(x!=sum1&&y!=sum2&&(y-sum2)%(x-sum1)==0){
ll num=(y-sum2)/(x-sum1);
for(int i=1;i<=n;i++){
ll a=num-b[i];
if(b[i]!=a&&(x-sum1-(a-b[i])*i)%(b[i]-a)==0){
ll k=(x-sum1-(a-b[i])*i)/(b[i]-a);
if(k>=1&&k<=n&&b[k]==a) ans++;
}
}
ans/=2;
}
printf("%lld\n",ans);
for(int i=1;i<=n;i++) mp[b[i]]=0;
}
return 0;
}
D - Traveler
这题一开始看到的题解很蒙,没有看懂,又找了一份题解感觉像是瞎搞的,找到了一个规律,
ai=(a(i-2)+1)*2+1,从n开始像小的枚举,存到栈里;从1开始遍历,遍历的时候能向后退就后退,不行就乘以2再不行就乘以2加1,这样就能列出所有的数来;但我不知道原理是啥,只能说是只适用于这个题的伪规律吧,看起来像瞎搞。。。
(2条消息) ZOJ 4103 浙江省第16届大学生程序设计竞赛 D题 Traveler 构造_weixin_30681121的博客-CSDN博客
#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,vis[100005];
vector<ll>v;
stack<ll>st;
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld",&t);
vis[0]=1;
while(t--){
scanf("%lld",&n);
v.clear();
for(int i=1;i<=n;i++) vis[i]=0;
while(n>1){
st.push(n);
if(n&1) n=(n-1)/2-1;
else n=n/2-1;
}
ll now=1;
while(1){
v.push_back(now);
vis[now]=1;
if(!vis[now-1]) now--;
else{
if(st.empty()) break;
else if(now*2==st.top()&&!vis[now*2]) now*=2,st.pop();
else if(now*2+1==st.top()&&!vis[now*2+1]) now=now*2+1,st.pop();
else{
if(!vis[now*2]) now*=2;
else if(!vis[now*2+1]) now=now*2+1;
}
}
}
for(int i=0;i<v.size();i++)
printf("%lld%c",v[i],i==v.size()-1?'\n':' ');
}
return 0;
}
C - Array in the Pocket
尽可能地让小数排在前面,如果碰到b[i]==a[i]了,那就尽量去后面找b[i]!=a[i]的位置填上,实在不行再去前面找,这个题实现方式没想到,,有些许复杂
(2条消息) C - Array in the Pocket (ZOJ - 4102)_hrbust_wgq的博客-CSDN博客
#include <bits/stdc++.h>
#define ll long long
#define lowbit(a) (a&(-a))
using namespace std;
const int mod=1000003;
const int inf=0x3f3f3f3f;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}
ll t,n,a[100005],ans[100005],cnt[100005];
vector<ll>pos[100005],res[100005];
set<ll>s;
int main(){
//freopen("in.txt","r",stdin);
scanf("%lld",&t);
while(t--){
scanf("%lld",&n);
s.clear();
bool flag=0;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]),cnt[i]=0,pos[i].clear(),res[i].clear(),ans[i]=0;
for(int i=1;i<=n;i++){
cnt[a[i]]++;
if(cnt[a[i]]>=n/2+1) flag=1;
s.insert(a[i]);
}
if(flag){
printf("Impossible\n");continue;
}
for(int i=1;i<=n;i++){
ll val=*s.begin();
if(s.size()==1&&val==a[i]){//去试后面的数可不可以
for(int j=i+1;j<=n;j++)
if(val!=a[j]){
ans[j]=val;
cnt[val]--;
}
vector<ll>poss,tmp;
for(int j=i;j<=n;j++){//看看后面有多少个不能填的数
if(a[j]==val) poss.push_back(j);
}
for(int j=i-1;j>=1;j--){//看看前面有多少个能填(换)的数
if(cnt[val]<=0) break;
if(ans[j]!=val&&a[j]!=val){
tmp.push_back(ans[j]);
ans[j]=val;
cnt[val]--;
}
}
ll len=poss.size();
for(int j=0;j<len;j++){//将val与之前的ans[j]换位置
ans[poss[j]]=tmp[j];
}
if(cnt[val]<=0) break;
}
else{
auto it=s.begin();
val=*it;
if(val==a[i]) it++;//不行就去试下一个
val=*it;
ans[i]=val;
cnt[val]--;
if(cnt[val]<=0) s.erase(val);
}
}
//将每个a[i]确定的数都放进一个vector里,方便后面排序(因为要输出字典序最小)
for(int i=1;i<=n;i++){
pos[a[i]].push_back(i);
res[a[i]].push_back(ans[i]);
}
for(int i=1;i<=n;i++){
if(pos[i].size()<=0) continue;
sort(pos[i].begin(),pos[i].end());
sort(res[i].begin(),res[i].end());
for(int j=0;j<pos[i].size();j++)
ans[pos[i][j]]=res[i][j];
}
for(int i=1;i<=n;i++){
printf("%lld%c",ans[i],i==n?'\n':' ');
}
}
return 0;
}