打得头皮发麻。。。
A
比赛的时候维护了每个phi的取模,卡常卡过了。听说有 O(n+log2n) O ( n + l o g 2 n ) 的牛逼算法,就学习了一下。看了下指数循环节,发现好像数据水了,直接mod都能过。
#include
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
ll mod[30]={
1000000007,
1000000006,
500000002,
243900800,
79872000,
19660800,
5242880,
2097152,
1048576,
524288,
262144,
131072,
65536,
32768,
16384,
8192,
4096,
2048,
1024,
512,
256,
128,
64,
32,
16,
8,
4,
2,
1,
1
};
inline ll power(ll p,ll mod){
ll ans=1;
ll base=2;
while(p){
if(p&1){
ans=ans*base%mod;
}
base=base*base%mod;
p>>=1;
}
return ans;
}
ll gmax(ll n,ll p){
ll ans=1;
ll base=n;
while(p){
if(p&1){
ans=ans*base;
ans=min(ans,1ll*inf);
}
base=base*base;
base=min(ans,1ll*inf);
p>>=1;
}
return ans;
}
int T;
char s[100003];
int typo[100003];
ll p[30];
int main(){
scanf("%d",&T);
while(T--){
scanf("%s",s);
memset(p,0,sizeof(p));
int len=strlen(s);
int tmp=0;
for(int i=len-1;i>=0;i--){
typo[i]=tmp;
if(s[i]=='2')tmp++;
}
ll ans=0;
tmp=0;
for(int i=0;iif(typo[i]>=28)typo[i]=28;
if(s[i]=='0'){
ans=(ans+1)%mod[typo[i]];
tmp=min(tmp+1,inf);
}
else if(s[i]=='1'){
ans=(ans*2+2)%mod[typo[i]];
tmp=min(tmp*2+2,inf);
}
else {
ans=(6*power(ans+(tmp>=mod[typo[i]+1])*mod[typo[i]+1],mod[typo[i]])-3+mod[typo[i]])%mod[typo[i]];
tmp=min(1ll*inf,6ll*gmax(2,tmp)-3);
}
}
printf("%lld\n",ans);
}
}
B
好像是n^2 dp下。
#include
using namespace std;
const int inf=1e9;
struct seg{
int l,r,w;
}a[2005];
bool cmp(seg a, seg b){
if(a.r!=b.r) return a.rreturn a.lint t,n,m;
int dp[2005][2005],tmp[2005][2005];
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=0; ifor(int j=0; j<=m; j++){
dp[i][j]=inf;
tmp[i][j]=inf;
}
scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].w);
}
sort(a,a+n,cmp);
for(int i=0; iif(a[i].l==1)
tmp[i][1]=a[i].w;
for(int j=1; j<=a[i].r; j++)
dp[i][j]=min(dp[i][j-1],tmp[i][j]);
}
for(int i=0; ifor(int k=0; kif(a[i].l==a[k].r+1)
tmp[i][a[i].l]=min(tmp[i][a[i].l],max(a[i].w,dp[k][a[k].r]));
if(a[i].l<=a[k].r)
tmp[i][a[k].r+1]=min(tmp[i][a[k].r+1],max(a[i].w+a[k].w,dp[k][a[i].l]));
}
for(int j=a[i].l; j<=a[i].r; j++)
dp[i][j]=min(dp[i][j-1],tmp[i][j]);
}
int ans=inf;
/*
for(int i=0; i
for(int i=0; iif (ans==inf)
printf("-1\n");
else printf("%d\n",ans);
}
return 0;
}
C
好像确实是标标准准的数位dp啊,尼玛这种玩意儿能不能不要做法各不相同啊,没有智商的solo选手做个蛋蛋啊。
#include
using namespace std;
typedef long long ll;
const int mod=1e9+7;
ll dp[61][121][2][2];
ll dig[61];
ll dfs(int pos,int status,int limit,int flag,int pre)
{
if(pos < 1)return abs(status);
if(!limit && dp[pos][status+60][flag][pre]!= -1)
return dp[pos][status+60][flag][pre];
int end = limit ? dig[pos] : 1;
ll ret = 0;
for(int i = 0;i <= end;i ++)
if(!flag){
ret+=dfs(pos-1,status,limit&&(i==end),i,i);
}
else {
if(i^pre){
ret+=dfs(pos-1,status-1,limit&&(i==end),1,i);
}
else ret+=dfs(pos-1,status+1,limit&&(i==end),1,i);
}
ret%=mod;
if(!limit)
dp[pos][status+60][flag][pre]= ret;
return ret;
}
int main(){
memset(dp,-1,sizeof(dp));
int T;
scanf("%d",&T);
while(T--){
ll n;
scanf("%lld",&n);
int pos=0;
while(n){
dig[++pos]=n%2;
n/=2;
}
printf("%lld\n",dfs(pos,0,1,0,0));
}
}
D
玩了一会发现奇数的都不行,偶数的按照正常人思路随便构造一下就完了。
#include
using namespace std;
int T,n;
int calc(int x,int y){
if(x+y==n+1){
if(x>y)return 1;
else return 0;
}
if(x+y1)return 1;
return -1;
}
int main(){
scanf("%d",&T);
while(T--){
scanf("%d",&n);
if(n%2)printf("impossible\n");
else {
printf("possible\n");
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d%c",calc(i,j),j==n?'\n':' ');
}
}
}
}
}
F
签到,随便预处理一下。
#include
using namespace std;
char s[2003][2003];
int n,m,T;
bool u[2003];
bool v[2003];
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",s[i]+1);
memset(u,false,sizeof(u));
memset(v,false,sizeof(v));
u[0]=v[0]=true;
for(int l=1,r=n;lif(!u[l-1])break;
bool ok=true;
for(int j=1;j<=m;j++){
ok&=(s[l][j]==s[r][j]);
}
u[l]=ok;
}
for(int l=1,r=m;lif(!v[l-1])break;
bool ok=true;
for(int i=1;i<=n;i++){
ok&=(s[i][l]==s[i][r]);
}
v[l]=ok;
}
int ans=0;
for(int i=1;i2;i++){
for(int j=1;j2;j++){
if(u[i]&&v[j])ans++;
}
}
printf("%d\n",ans);
}
}
G
签到,搞两个map,二分一下。
#include
using namespace std;
int n,m,T;
map<int,int>mp;
map<int,int>cnt;
int pre[100003];
int sum[100003];
int tot;
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
mp.clear();
cnt.clear();
tot=0;
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
mp[x]++;
}
for(auto it=mp.begin();it!=mp.end();it++){
int x=it->first;
int tim=it->second;
cnt[tim]++;
pre[++tot]=tim;
}
sort(pre+1,pre+1+tot);
for(int i=1;i<=tot;i++){
sum[i]=pre[i]+sum[i-1];
}
int ans=-1;
for(auto it=mp.begin();it!=mp.end();it++){
int x=it->first;
int tim=it->second;
int up=cnt[tim]+pre+1+tot-upper_bound(pre+1,pre+1+tot,tim);
int res=up*(tim-1)+1;
int pos=lower_bound(pre+1,pre+1+tot,tim)-pre-1;
res+=sum[pos];
if(res>=n-m){
ans=max(ans,x);
}
}
printf("%d\n",ans);
}
}
J
每个点记录从左边往他连线覆盖的区间长度。然后每个点不断地连当前区间左边第一个,扩大区间直到覆盖了初始位置,这样总的连边数是 O(n) O ( n ) 的。用个堆跑一下拓扑排序就行了。
#include
using namespace std;
int n,m;
int a[200003];
int l[200003];
int d[200003];
int ans[200003];
int tot;
vector<int>g[200003];
priority_queueint,int>,vectorint ,int> >,greaterint,int> > >pq;
inline bool check(int r,int len,int x){
int dis=r-x;
if(dis<0)dis+=n;
return disint main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
m=0;
tot=0;
for(int i=0;iscanf("%d",&a[i]);
if(a[i]!=-1)m++;
d[i]=0;
l[i]=1;
g[i].clear();
}
bool ok=true;
for(int i=0;iif(a[i]==-1){
continue;
}
if(a[i]%n==i){
continue;
}
int st=a[i]%n;
int j=(i-1+n)%n;
while(1){
if(a[j]==-1){
ok=false;
break;
}
g[j].push_back(i);
d[i]++;
l[i]+=l[j];
if(check(i,l[i],st))break;
j-=l[j];
if(j<0)j+=n;
}
if(!ok)break;
}
if(!ok){
printf("-1\n");
continue;
}
for(int i=0;iif(a[i]!=-1&&d[i]==0){
pq.push(make_pair(a[i],i));
}
}
while(!pq.empty()){
pair<int,int>pr=pq.top();
pq.pop();
ans[++tot]=pr.first;
int u=pr.second;
for(int i=0;iint v=g[u][i];
d[v]--;
if(!d[v])pq.push(make_pair(a[v],v));
}
}
if(tot!=m){
printf("-1\n");
}
else {
if(m==0)printf("\n");
for(int i=1;i<=m;i++)printf("%d%c",ans[i],i==m?'\n':' ');
}
}
}