2022ccpc网络赛
一坨*这个人
全队都犯病了,没啥好说的
A(签到 模拟)
签到题
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
int num=0;
int cnt[4][15];
int readx()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
cnt[num][x]++;
if(ch=='\n') num++;
if(num==4) return 0;
return 1;
}
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
vi deck,tmp;
int main()
{
while(readx());
int m=read(),val,cur=0;char s[5];
while(m--)
{
scanf("%s",s+1);
if(s[1]=='S') val=read();
if(s[1]!='?')
{
int k=read();
for(auto x:tmp) deck.push_back(x);
tmp.clear();
rep(i,1,k) {int x=read();tmp.push_back(x);cnt[cur][x]--;}
}
else
{
int flg=1;
for(auto x:tmp) if(x!=val) flg=0;
int id=flg?cur:(cur+3)%4;
for(auto x:tmp) cnt[id][x]++;
for(auto x:deck) cnt[id][x]++;
deck.clear();tmp.clear();
}
cur=(cur+1)%4;
}
rep(i,0,3) {rep(j,1,13) rep(k,1,cnt[i][j]) cout<<j<<' ';puts("");}
}
C(简单结论)
奇数因子显然无意义,手动模拟几轮之后容易得到规律
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
ll a, b;
scanf("%lld%lld", &a, &b);
ll i = 0;
__int128 j = 1;
while (true)
{
++i;
j *= 2;
if (b %j != 0)
{
printf("%lld %lld\n", i, 0LL);
break;
}
j *= 2;
if (a %j != 0)
{
printf("%lld %lld\n", i, 1LL);
break;
}
}
}
return 0;
}
E(dp)
由于模式串中大写字母很少,直接暴力匹配dp即可,复杂度为\(O(200|S|)\)
令\(f[i][j]\)表示模式串匹配到第\(i\)个大写字母,匹配串匹配到\(j\)位时匹配串匹配的最长长度,分两种情况转移即可:
- 当前大写字母与模式串\(j\)位相同,从\(f[i][j-1]+1\)转移
- 上一个大写字母之间的小写字符串与\(t(j-len+1,j)\)相同,从\(f[i-1][j-len]+len\)转移,用哈希判断字符串相等即可
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
const int inf=1e9;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
const int MOD=1000000007,bas=233;
inline int mul(int a,int b){return 1LL*a*b%MOD;}
inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;}
inline int mns(int a,int b){return a-b<0?a-b+MOD:a-b;}
int n,m,hsh[MAXN],pw[MAXN];
int f[210][MAXN];
char s[MAXN],t[MAXN];
vi pos,val;
inline int getw(int l,int r){return mns(hsh[r],mul(hsh[l-1],pw[r-l+1]));}
void solve()
{
scanf("%s%s",s+1,t+1);
n=strlen(s+1),m=strlen(t+1);
pw[0]=1;rep(i,1,n) hsh[i]=pls(mul(hsh[i-1],bas),s[i]-'a'+1),pw[i]=mul(pw[i-1],bas);
pos.clear();val.clear();
pos.push_back(0);val.push_back(0);
int x=0;
rep(i,1,m+1)
if(i==m+1||isupper(t[i]))
{
pos.push_back(i);val.push_back(x);
t[i]=t[i]-'A'+'a';
x=0;
}
else x=pls(mul(x,bas),t[i]-'a'+1);
m=pos.size()-1;
int ans=0;
rep(i,1,m) rep(j,0,n)
{
f[i][j]=-inf;
if(j&&t[pos[i]]==s[j]) f[i][j]=f[i][j-1]+1;
int len=pos[i]-pos[i-1]-1;
if(j>=len&&(!len||getw(j-len+1,j)==val[i]))
f[i][j]=max(f[i][j],f[i-1][j-len]+len);
if(i==m) ans=max(ans,f[i][j]);
}
printf("%d\n",ans);
}
int main()
{
rep(T,1,read()) solve();
}
G(记忆化搜索)
对正反串分别建立trie树,令\(f[x][y]\)表示在两个树的\(x,y\)节点上的最长匹配长度,当点对被重复访问时说明出现了循环,答案为inf
使用dfs转移(注意考虑串的结尾向trie树根的转移
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
struct trie
{
int tr[5050][26],tot,ed[5050];
trie():tot(0){memset(tr,0,sizeof(tr));memset(ed,0,sizeof(ed));}
void ins(char *s,int len)
{
int pos=0,ch;
rep(i,0,len-1)
{
ch=s[i]-'a';
if(!tr[pos][ch]) tr[pos][ch]=++tot;
pos=tr[pos][ch];
}
ed[pos]|=1;
}
}t1,t2;
int n,f[5050][5050],ans,cnt=0;
char s[5050];
void dfs(int x,int y)
{
if(t1.ed[x]&&t2.ed[y]) {puts("INF");exit(0);}
ans=max(ans,f[x][y]);
rep(i,0,25)
{
if(t1.tr[x][i]&&t2.tr[y][i])
{
if(~f[t1.tr[x][i]][t2.tr[y][i]]) {puts("INF");exit(0);}
f[t1.tr[x][i]][t2.tr[y][i]]=f[x][y]+1;
dfs(t1.tr[x][i],t2.tr[y][i]);
}
if(t1.ed[x]&&t1.tr[0][i]&&t2.tr[y][i])
{
if(~f[t1.tr[0][i]][t2.tr[y][i]]) {puts("INF");exit(0);}
f[t1.tr[0][i]][t2.tr[y][i]]=f[x][y]+1;
dfs(t1.tr[0][i],t2.tr[y][i]);
}
if(t2.ed[y]&&t2.tr[0][i]&&t1.tr[x][i])
{
if(~f[t1.tr[x][i]][t2.tr[0][i]]) {puts("INF");exit(0);}
f[t1.tr[x][i]][t2.tr[0][i]]=f[x][y]+1;
dfs(t1.tr[x][i],t2.tr[0][i]);
}
}
}
int main()
{
n=read();
rep(i,1,n)
{
scanf("%s",s);int len=strlen(s);
t1.ins(s,len);
reverse(s,s+len);
t2.ins(s,len);
}
rep(i,0,t1.tot) rep(j,0,t2.tot) f[i][j]=-1;
f[0][0]=0;
dfs(0,0);
cout<<ans<<'\n';
}
H(pollard rho)
简单推一下式子容易发现\(x\)一定是\(K\)的因子,而因子数实际上很小,用\(pollard\ rho\)得到\(K\)的所有质因子,再暴力组合枚举所有因子,复杂度为\(O(K^{\frac{1}{4}})\)
对于每个\(x\)暴力判断即可
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline ll mul(ll a,ll b,ll mod){return (__int128)a*b%mod;}
ll qp(ll x,ll t,ll mod,ll res=1)
{
for(;t;t>>=1,x=mul(x,x,mod))
if(t&1) res=mul(res,x,mod);
return res;
}
bool miller_rabin(ll n)
{
if(n==1) return 0;
if(n<=3) return 1;
ll m=n-1,b=0;
while(!(m&1)) m>>=1,b++;
rep(i,1,15)
{
ll x=qp(rand()%(n-2)+2,m,n);
if(x==1||x==n-1) continue;
rep(i,1,b-1) {x=mul(x,x,n);if(x==n-1) break;}
if(x!=n-1) return 0;
}
return 1;
}
ll pollard_rho(ll n)
{
ll s=0,t=0,c=rand()%(n-1)+1,val=1;
for(int lim=1;;lim*=2,s=t,val=1) rep(i,1,lim)
{
t=(mul(t,t,n)+c)%n;
val=mul(val,abs(t-s),n);
if(i%127==0||i==lim)
{
ll d=__gcd(val,n);
if(d>1) return d;
}
}
}
vector<ll> fac,ans;
void getFac(ll n)
{
if(n==1) return ;
if(miller_rabin(n)) {fac.push_back(n);return ;}
ll m=n;
while(m==n) m=pollard_rho(n);
while(n%m==0) n/=m;
getFac(n);getFac(m);
}
ll L,R,K;
int len;
bool check(ll x)
{
ll a=(L+x-1)/x,b=R/x,m=b-a+1;
if(m>=50) return 0;
ll y=(1LL<<m-1)*(b+a)*m/2;
return y==K/x;
}
void dfs(int i,ll now,ll n)
{
if(i==len) {if(check(now)) ans.push_back(now);return ;}
dfs(i+1,now,n);
while(n%fac[i]==0)
{
now*=fac[i],n/=fac[i];
dfs(i+1,now,n);
}
}
void solve()
{
scanf("%lld%lld%lld",&L,&R,&K);
fac.clear();ans.clear();
getFac(K);
sort(fac.begin(),fac.end());
fac.erase(unique(fac.begin(),fac.end()),fac.end());
len=fac.size();
dfs(0,1,K);
if(ans.empty()) {puts("No Solution");return;}
printf("%d\n",(int)ans.size());
sort(ans.begin(),ans.end());
for(auto x:ans) printf("%lld%c",x," \n"[x==ans.back()]);
}
int main()
{
rep(T,1,read()) solve();
}
I(差分)
不妨令所有\(a_i<b_i\),考虑将传送门建在\((x,y),x<y\) 两个位置的答案:
考虑固定\(x\),根据\(x\)与\(a_i\)的大小关系,\(\min\)部分可以写为:
将\(2a_i-b_i-x\)与\(x-b_i\)记为\(w\),显然仅当\(w<0\)时,\(\min\)才有意义
固定\(x\),利用二阶差分,对于每个运输计划在\(b_i-|w|+1,\ b_i+1,\ b_i+|w|+1\)处分别标记,求关于\(y\)的函数值,这样得到了一个\(O(nm)\)的算法,考虑继续优化
注意到对于\(x+1\le a_i\)的情况,当\(x++\)时,\(|w|++\),两侧的标记分别左移右移;\(x\ge a_i\)同理
只有当\(x=a_i\)时,类型被改变,标记的移动方式也会发生改变,对每个\(i\)在\(a_i\)处进行转换即可
同时,由于需要时刻满足\(w<0\),则每个\(i\)对答案有贡献的合法\(x\)区间为\([2a_i-b_i+1,b_i)\),分别在对应位置插入或删除,还需要考虑插入点与\(a_i\)的关系,记录一下当前属于哪个类别
还需要注意\(b_i-|w|+1,\ b_i+|w|+1\)的取值范围,在二阶差分时考虑更大的区间\((-n,2n]\)
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
using namespace std;
typedef long long ll;
typedef double db;
typedef long double ld;
typedef vector<int> vi;
const int MAXN=200100;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m;
ll ar[50010],*h1=ar+3500,*h2=ar+13500,*h3=ar+23500,*h4=ar+33500;
bool tag[MAXN];
ll p[20010],bas,ans,*d=p+3500,*sum=p+13500;
vi v1[3010],v2[3010],v3[3010];
struct seg{int l,r,w;}g[MAXN];
void ins(int i,int p)
{
int w;
if(!tag[i])
{
w=g[i].r+p-2*g[i].l;
h1[g[i].r-w+1]-=g[i].w;
d[g[i].r+1]+=g[i].w<<1;
h2[g[i].r+w+1]-=g[i].w;
}
else
{
w=g[i].r-p;
h3[g[i].r-w+1]-=g[i].w;
d[g[i].r+1]+=g[i].w<<1;
h4[g[i].r+w+1]-=g[i].w;
}
}
void chg(int i)
{
int w=g[i].r-g[i].l;
tag[i]=1;
h1[g[i].r-w+1]+=g[i].w;
h3[g[i].r-w+1]-=g[i].w;
h2[g[i].r+w+1]+=g[i].w;
h4[g[i].r+w+1]-=g[i].w;
}
void del(int i)
{
if(!tag[i])
{
h1[g[i].r+1]+=g[i].w;
d[g[i].r+1]-=g[i].w<<1;
h2[g[i].r+1]+=g[i].w;
}
else
{
h3[g[i].r+1]+=g[i].w;
d[g[i].r+1]-=g[i].w<<1;
h4[g[i].r+1]+=g[i].w;
}
}
int main()
{
n=read(),m=read();
rep(i,1,m)
{
g[i].l=read(),g[i].r=read(),g[i].w=read();
if(g[i].l==g[i].r) continue;
if(g[i].l>g[i].r) swap(g[i].l,g[i].r);
bas+=1LL*(g[i].r-g[i].l)*g[i].w;
if(2*g[i].l-g[i].r+1<1) ins(i,1);
else v1[2*g[i].l-g[i].r+1].push_back(i);
if(2*g[i].l-g[i].r+1<g[i].l) v2[g[i].l].push_back(i);
else tag[i]=1;
v3[g[i].r].push_back(i);
}
rep(x,1,n)
{
for(auto i:v1[x]) ins(i,x);
for(auto i:v3[x]) del(i);
//rep(i,-n+1,n) cout<<d[i]+h1[i]+h2[i]+h3[i]+h4[i]<<" ";puts("");
rep(i,-n+1,n) sum[i]=d[i]+h1[i]+h2[i]+h3[i]+h4[i]+sum[i-1];
rep(i,-n+1,n) sum[i]+=sum[i-1];
rep(i,1,n) ans=min(ans,sum[i]);
for(auto i:v2[x]) chg(i);
rep(i,-n+1,2*n) h1[i]=h1[i+1],h4[i]=h4[i+1];
dwn(i,2*n,-n+1) h2[i]=h2[i-1],h3[i]=h3[i-1];
}
printf("%lld\n",bas+ans);
}
K(结论/瞎搞)
因为本金无限大,每次花两倍的钱去赌,因为概率最小为\(0.01\)且随机,5000次里肯定会赢一次
import sys
y=eval(input().split()[0])
while 1:
print(y)
sys.stdout.flush()
x=eval(input())
y*=2
if x==2:
break
M(签到)
签到题
#include<bits/stdc++.h>
#define rep(i,s,t) for(int i=(s),i##end=(t);i<=i##end;++i)
#define dwn(i,s,t) for(int i=(s),i##end=(t);i>=i##end;--i)
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
typedef vector<int> vi;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
int n=read(),k=read();
printf("%d\n",(n-1+k-2)/(k-1));
}